library(swimplot) library(coxphf) library(grid) library(gtable) library(readr) library(mosaic) library(dplyr) library(survival) library(survminer) library(gridtext) library(ggplot2) library(scales) library(officer) library(ggthemes) library(tidyverse) library(gtsummary) library(flextable) library(parameters) library(car) library(grid) library(ComplexHeatmap) library(readxl) library(janitor) library(rms) library(DT)

#Demographics Table

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data_subset <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    PrimSite,
    Mets.Type,
    Hepatectomy,
    NumLiverMetsGroup,
    SizeLiverMetsmmGroup,
    pT,
    pN,
    ACT,
    Oxaliplatin.History,
    Postop.Complication,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.months) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    PrimSite = factor(PrimSite, levels = c("Right-sided colon", "Left-sided colon")),
    Mets.Type = factor(Mets.Type, levels = c("Synchronous", "Metachronous")),
    Hepatectomy = factor(Hepatectomy, levels = c("Minor", "Major")),
    NumLiverMetsGroup = factor(NumLiverMetsGroup, levels = c("1", "≥2")),
    SizeLiverMetsmmGroup = factor(SizeLiverMetsmmGroup, levels = c("<50", "≥50")),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    Oxaliplatin.History = factor(Oxaliplatin.History, levels = c("No", "Yes")),
    Postop.Complication = factor(Postop.Complication, levels = c("No", "Yes")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.months = as.numeric(OS.months))
table1 <- circ_data_subset %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
table1
Characteristic N = 1901
Age 68 (34 - 85)
Gender
    Male 118 (62%)
    Female 72 (38%)
ECOG
    0 186 (98%)
    1 4 (2.1%)
PrimSite
    Right-sided colon 50 (26%)
    Left-sided colon 140 (74%)
Mets.Type
    Synchronous 64 (34%)
    Metachronous 126 (66%)
Hepatectomy
    Minor 159 (84%)
    Major 31 (16%)
NumLiverMetsGroup
    1 121 (64%)
    ≥2 69 (36%)
SizeLiverMetsmmGroup
    <50 180 (95%)
    ≥50 10 (5.3%)
pT
    T1-T2 23 (12%)
    T3-T4 167 (88%)
pN
    N0 77 (41%)
    N1-N2 113 (59%)
ACT
    Adjuvant Chemotherapy 48 (25%)
    Observation 142 (75%)
Oxaliplatin.History 50 (26%)
Postop.Complication 23 (12%)
BRAF.V600E
    BRAF wt 188 (99%)
    BRAF V600E 2 (1.1%)
RAS
    RAS wt 106 (56%)
    RAS mut 84 (44%)
MSI
    MSS 188 (99%)
    MSI-High 2 (1.1%)
RFS.Event
    Recurrence 95 (50%)
    No Recurrence 95 (50%)
OS.months 24 (1 - 48)
1 Median (Range); n (%)
fit1 <- as_flex_table(
  table1,
  include = everything(),
  return_calls = FALSE,
  strip_md_bold = TRUE)
Warning: The `strip_md_bold` argument of `as_flex_table()` is deprecated as of gtsummary 1.6.0.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
fit1

Characteristic

N = 1901

Age

68 (34 - 85)

Gender

Male

118 (62%)

Female

72 (38%)

ECOG

0

186 (98%)

1

4 (2.1%)

PrimSite

Right-sided colon

50 (26%)

Left-sided colon

140 (74%)

Mets.Type

Synchronous

64 (34%)

Metachronous

126 (66%)

Hepatectomy

Minor

159 (84%)

Major

31 (16%)

NumLiverMetsGroup

1

121 (64%)

≥2

69 (36%)

SizeLiverMetsmmGroup

<50

180 (95%)

≥50

10 (5.3%)

pT

T1-T2

23 (12%)

T3-T4

167 (88%)

pN

N0

77 (41%)

N1-N2

113 (59%)

ACT

Adjuvant Chemotherapy

48 (25%)

Observation

142 (75%)

Oxaliplatin.History

50 (26%)

Postop.Complication

23 (12%)

BRAF.V600E

BRAF wt

188 (99%)

BRAF V600E

2 (1.1%)

RAS

RAS wt

106 (56%)

RAS mut

84 (44%)

MSI

MSS

188 (99%)

MSI-High

2 (1.1%)

RFS.Event

Recurrence

95 (50%)

No Recurrence

95 (50%)

OS.months

24 (1 - 48)

1Median (Range); n (%)

save_as_docx(fit1, path= "~/Downloads/table1.docx")

#Demographics Table by MRD ctDNA Status

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data_subset1 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    PrimSite,
    Mets.Type,
    Hepatectomy,
    NumLiverMetsGroup,
    SizeLiverMetsmmGroup,
    pT,
    pN,
    ACT,
    Oxaliplatin.History,
    Postop.Complication,
    BRAF.V600E,
    RAS,
    MSI) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    PrimSite = factor(PrimSite, levels = c("Right-sided colon", "Left-sided colon")),
    Mets.Type = factor(Mets.Type, levels = c("Synchronous", "Metachronous")),
    Hepatectomy = factor(Hepatectomy, levels = c("Minor", "Major")),
    NumLiverMetsGroup = factor(NumLiverMetsGroup, levels = c("1", "≥2")),
    SizeLiverMetsmmGroup = factor(SizeLiverMetsmmGroup, levels = c("<50", "≥50")),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    Oxaliplatin.History = factor(Oxaliplatin.History, levels = c("No", "Yes")),
    Postop.Complication = factor(Postop.Complication, levels = c("No", "Yes")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")))

circ_data1 <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data1 <- circ_data1[circ_data1$LiverMets=="TRUE",]

circ_data_subset2 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    PrimSite,
    Mets.Type,
    Hepatectomy,
    NumLiverMetsGroup,
    SizeLiverMetsmmGroup,
    pT,
    pN,
    ACT,
    Oxaliplatin.History,
    Postop.Complication,
    BRAF.V600E,
    RAS,
    MSI,
    ctDNA.MRD) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    PrimSite = factor(PrimSite, levels = c("Right-sided colon", "Left-sided colon")),
    Mets.Type = factor(Mets.Type, levels = c("Synchronous", "Metachronous")),
    Hepatectomy = factor(Hepatectomy, levels = c("Minor", "Major")),
    NumLiverMetsGroup = factor(NumLiverMetsGroup, levels = c("1", "≥2")),
    SizeLiverMetsmmGroup = factor(SizeLiverMetsmmGroup, levels = c("<50", "≥50")),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    Oxaliplatin.History = factor(Oxaliplatin.History, levels = c("No", "Yes")),
    Postop.Complication = factor(Postop.Complication, levels = c("No", "Yes")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 1901
Age 68 (34 - 85)
Gender
    Male 118 (62%)
    Female 72 (38%)
ECOG
    0 186 (98%)
    1 4 (2.1%)
PrimSite
    Right-sided colon 50 (26%)
    Left-sided colon 140 (74%)
Mets.Type
    Synchronous 64 (34%)
    Metachronous 126 (66%)
Hepatectomy
    Minor 159 (84%)
    Major 31 (16%)
NumLiverMetsGroup
    1 121 (64%)
    ≥2 69 (36%)
SizeLiverMetsmmGroup
    <50 180 (95%)
    ≥50 10 (5.3%)
pT
    T1-T2 23 (12%)
    T3-T4 167 (88%)
pN
    N0 77 (41%)
    N1-N2 113 (59%)
ACT
    Adjuvant Chemotherapy 48 (25%)
    Observation 142 (75%)
Oxaliplatin.History 50 (26%)
Postop.Complication 23 (12%)
BRAF.V600E
    BRAF wt 188 (99%)
    BRAF V600E 2 (1.1%)
RAS
    RAS wt 106 (56%)
    RAS mut 84 (44%)
MSI
    MSS 188 (99%)
    MSI-High 2 (1.1%)
1 Median (Range); n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # Subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p(test = all_categorical() ~ "fisher.test", pvalue_fun = ~style_pvalue(p.adjust(.x, method = "bonferroni"))) %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE, N = 1291 POSITIVE, N = 611 p-value2
Age 69 (37 - 85) 68 (34 - 84) >0.9
Gender

>0.9
    Male 83 (64%) 35 (57%)
    Female 46 (36%) 26 (43%)
ECOG

>0.9
    0 127 (98%) 59 (97%)
    1 2 (1.6%) 2 (3.3%)
PrimSite

0.6
    Right-sided colon 40 (31%) 10 (16%)
    Left-sided colon 89 (69%) 51 (84%)
Mets.Type

0.015
    Synchronous 33 (26%) 31 (51%)
    Metachronous 96 (74%) 30 (49%)
Hepatectomy

>0.9
    Minor 112 (87%) 47 (77%)
    Major 17 (13%) 14 (23%)
NumLiverMetsGroup

0.010
    1 93 (72%) 28 (46%)
    ≥2 36 (28%) 33 (54%)
SizeLiverMetsmmGroup

>0.9
    <50 123 (95%) 57 (93%)
    ≥50 6 (4.7%) 4 (6.6%)
pT

>0.9
    T1-T2 16 (12%) 7 (11%)
    T3-T4 113 (88%) 54 (89%)
pN

0.3
    N0 60 (47%) 17 (28%)
    N1-N2 69 (53%) 44 (72%)
ACT

>0.9
    Adjuvant Chemotherapy 33 (26%) 15 (25%)
    Observation 96 (74%) 46 (75%)
Oxaliplatin.History 39 (30%) 11 (18%) >0.9
Postop.Complication 10 (7.8%) 13 (21%) 0.2
BRAF.V600E

>0.9
    BRAF wt 127 (98%) 61 (100%)
    BRAF V600E 2 (1.6%) 0 (0%)
RAS

>0.9
    RAS wt 74 (57%) 32 (52%)
    RAS mut 55 (43%) 29 (48%)
MSI

>0.9
    MSS 128 (99%) 60 (98%)
    MSI-High 1 (0.8%) 1 (1.6%)
1 Median (Range); n (%)
2 Wilcoxon rank sum test; Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic Table 1 Table 2
N = 1901 NEGATIVE, N = 1291 POSITIVE, N = 611 p-value2
Age 68 (34 - 85) 69 (37 - 85) 68 (34 - 84) >0.9
Gender


>0.9
    Male 118 (62%) 83 (64%) 35 (57%)
    Female 72 (38%) 46 (36%) 26 (43%)
ECOG


>0.9
    0 186 (98%) 127 (98%) 59 (97%)
    1 4 (2.1%) 2 (1.6%) 2 (3.3%)
PrimSite


0.6
    Right-sided colon 50 (26%) 40 (31%) 10 (16%)
    Left-sided colon 140 (74%) 89 (69%) 51 (84%)
Mets.Type


0.015
    Synchronous 64 (34%) 33 (26%) 31 (51%)
    Metachronous 126 (66%) 96 (74%) 30 (49%)
Hepatectomy


>0.9
    Minor 159 (84%) 112 (87%) 47 (77%)
    Major 31 (16%) 17 (13%) 14 (23%)
NumLiverMetsGroup


0.010
    1 121 (64%) 93 (72%) 28 (46%)
    ≥2 69 (36%) 36 (28%) 33 (54%)
SizeLiverMetsmmGroup


>0.9
    <50 180 (95%) 123 (95%) 57 (93%)
    ≥50 10 (5.3%) 6 (4.7%) 4 (6.6%)
pT


>0.9
    T1-T2 23 (12%) 16 (12%) 7 (11%)
    T3-T4 167 (88%) 113 (88%) 54 (89%)
pN


0.3
    N0 77 (41%) 60 (47%) 17 (28%)
    N1-N2 113 (59%) 69 (53%) 44 (72%)
ACT


>0.9
    Adjuvant Chemotherapy 48 (25%) 33 (26%) 15 (25%)
    Observation 142 (75%) 96 (74%) 46 (75%)
Oxaliplatin.History 50 (26%) 39 (30%) 11 (18%) >0.9
Postop.Complication 23 (12%) 10 (7.8%) 13 (21%) 0.2
BRAF.V600E


>0.9
    BRAF wt 188 (99%) 127 (98%) 61 (100%)
    BRAF V600E 2 (1.1%) 2 (1.6%) 0 (0%)
RAS


>0.9
    RAS wt 106 (56%) 74 (57%) 32 (52%)
    RAS mut 84 (44%) 55 (43%) 29 (48%)
MSI


>0.9
    MSS 188 (99%) 128 (99%) 60 (98%)
    MSI-High 2 (1.1%) 1 (0.8%) 1 (1.6%)
1 Median (Range); n (%)
2 Wilcoxon rank sum test; Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE,
  strip_md_bold = TRUE)
fit1

Table 1

Table 2

Characteristic

N = 1901

NEGATIVE, N = 1291

POSITIVE, N = 611

p-value2

Age

68 (34 - 85)

69 (37 - 85)

68 (34 - 84)

>0.9

Gender

>0.9

Male

118 (62%)

83 (64%)

35 (57%)

Female

72 (38%)

46 (36%)

26 (43%)

ECOG

>0.9

0

186 (98%)

127 (98%)

59 (97%)

1

4 (2.1%)

2 (1.6%)

2 (3.3%)

PrimSite

0.6

Right-sided colon

50 (26%)

40 (31%)

10 (16%)

Left-sided colon

140 (74%)

89 (69%)

51 (84%)

Mets.Type

0.015

Synchronous

64 (34%)

33 (26%)

31 (51%)

Metachronous

126 (66%)

96 (74%)

30 (49%)

Hepatectomy

>0.9

Minor

159 (84%)

112 (87%)

47 (77%)

Major

31 (16%)

17 (13%)

14 (23%)

NumLiverMetsGroup

0.010

1

121 (64%)

93 (72%)

28 (46%)

≥2

69 (36%)

36 (28%)

33 (54%)

SizeLiverMetsmmGroup

>0.9

<50

180 (95%)

123 (95%)

57 (93%)

≥50

10 (5.3%)

6 (4.7%)

4 (6.6%)

pT

>0.9

T1-T2

23 (12%)

16 (12%)

7 (11%)

T3-T4

167 (88%)

113 (88%)

54 (89%)

pN

0.3

N0

77 (41%)

60 (47%)

17 (28%)

N1-N2

113 (59%)

69 (53%)

44 (72%)

ACT

>0.9

Adjuvant Chemotherapy

48 (25%)

33 (26%)

15 (25%)

Observation

142 (75%)

96 (74%)

46 (75%)

Oxaliplatin.History

50 (26%)

39 (30%)

11 (18%)

>0.9

Postop.Complication

23 (12%)

10 (7.8%)

13 (21%)

0.2

BRAF.V600E

>0.9

BRAF wt

188 (99%)

127 (98%)

61 (100%)

BRAF V600E

2 (1.1%)

2 (1.6%)

0 (0%)

RAS

>0.9

RAS wt

106 (56%)

74 (57%)

32 (52%)

RAS mut

84 (44%)

55 (43%)

29 (48%)

MSI

>0.9

MSS

188 (99%)

128 (99%)

60 (98%)

MSI-High

2 (1.1%)

1 (0.8%)

1 (1.6%)

1Median (Range); n (%)

2Wilcoxon rank sum test; Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#ctDNA Detection Rates by Window and Stages

#ctDNA at Baseline
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Baseline!="",]
circ_data$ctDNA.Baseline <- factor(circ_data$ctDNA.Baseline, levels=c("NEGATIVE","POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("IV"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Baseline == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at MRD Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("IV"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.MRD == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.MRD, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.MRD == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Surveillance %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("IV"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Surveillance == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA Detection Rates by Window and Synchronicity

#ctDNA at Baseline
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Baseline!="",]
circ_data$ctDNA.Baseline <- factor(circ_data$ctDNA.Baseline, levels=c("NEGATIVE","POSITIVE"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline == "POSITIVE", by=list(circ_data$Mets.Type), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline, by=list(circ_data$Mets.Type), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Baseline == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at MRD Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.MRD == "POSITIVE", by=list(circ_data$Mets.Type), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.MRD, by=list(circ_data$Mets.Type), FUN=length)
combined_data <- data.frame(
  Mets.Type = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.MRD == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Mets.Type = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Surveillance %in% c("NEGATIVE", "POSITIVE"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance == "POSITIVE", by=list(circ_data$Mets.Type), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance, by=list(circ_data$Mets.Type), FUN=length)
combined_data <- data.frame(
  Mets.Type = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Surveillance == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Mets.Type = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#Barplot with Detection Rates at the MRD and Surveillance Windows by Synchronicity

#Detection rate at the Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
contingency_table <- table(circ_data$Mets.Type, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 10.707, df = 1, p-value = 0.001067
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.0009273
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 1.507768 5.977774
sample estimates:
odds ratio 
  2.987004 
print(contingency_table)
              
               Negative Positive
  Metachronous       96       30
  Synchronous        33       31
p_values <- c(chi_square_test$p.value, fisher_exact_test$p.value)
p_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_adjusted) <- c("Chi-Square Test", "Fisher's Exact Test")
print(p_adjusted)
    Chi-Square Test Fisher's Exact Test 
        0.002134653         0.001854561 
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Patients with CLM - ctDNA MRD Window", 
       x = "Synchronicity", 
       y = "Patients (%)", 
       fill = "ctDNA MRD Window",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value), "; Bonferroni corrected p-value: ", format.pval(p_adjusted["Chi-Square Test"]))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size


#Detection rate at the Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
contingency_table <- table(circ_data$Mets.Type, circ_data$ctDNA.Surveillance)
chi_square_test <- chisq.test(contingency_table)
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 4.4449, df = 1, p-value = 0.03501
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.03232
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 1.048856 4.688132
sample estimates:
odds ratio 
  2.210114 
print(contingency_table)
              
               Negative Positive
  Metachronous       72       30
  Synchronous        27       25
p_values <- c(chi_square_test$p.value, fisher_exact_test$p.value)
p_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_adjusted) <- c("Chi-Square Test", "Fisher's Exact Test")
print(p_adjusted)
    Chi-Square Test Fisher's Exact Test 
         0.07001175          0.06464745 
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Patients with CLM - ctDNA Surveillance Window", 
       x = "Synchronicity", 
       y = "Patients (%)", 
       fill = "ctDNA Surveillance Window",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value), "; Bonferroni corrected p-value: ", format.pval(p_adjusted["Chi-Square Test"]))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size

#Barplot with Detection Rates at pre-op and ctDNA MRD by pre-OP CEA

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data$ctDNA.Baseline <- factor(circ_data$ctDNA.Baseline, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
contingency_table <- table(circ_data$CEA.Baseline, circ_data$ctDNA.Baseline)
chi_square_test <- chisq.test(contingency_table)
Warning in stats::chisq.test(x, y, ...) :
  Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 0.038105, df = 1, p-value = 0.8452
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.5858
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
   0.1293152 150.9263898
sample estimates:
odds ratio 
  2.524321 
print(contingency_table)
          
           Negative Positive
  Normal          2       82
  Elevated        1      104
p_values <- c(chi_square_test$p.value, fisher_exact_test$p.value)
p_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_adjusted) <- c("Chi-Square Test", "Fisher's Exact Test")
print(p_adjusted)
    Chi-Square Test Fisher's Exact Test 
                  1                   1 
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Pre-op CEA & Pre-op ctDNA", 
       x = "Pre-op CEA", 
       y = "Patients (%)", 
       fill = "ctDNA pre-op",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value), "; Bonferroni corrected p-value: ", format.pval(p_adjusted["Chi-Square Test"]))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size


rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
contingency_table <- table(circ_data$CEA.Baseline, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 2.8368e-30, df = 1, p-value = 1
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 1
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 0.5168345 1.9328504
sample estimates:
odds ratio 
 0.9969296 
print(contingency_table)
          
           Negative Positive
  Normal         57       27
  Elevated       72       34
p_values <- c(chi_square_test$p.value, fisher_exact_test$p.value)
p_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_adjusted) <- c("Chi-Square Test", "Fisher's Exact Test")
print(p_adjusted)
    Chi-Square Test Fisher's Exact Test 
                  1                   1 
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Pre-op CEA & ctDNA MRD", 
       x = "Pre-op CEA", 
       y = "Patients (%)", 
       fill = "ctDNA at MRD",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value), "; Bonferroni corrected p-value: ", format.pval(p_adjusted["Chi-Square Test"]))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size

#DFS by ctDNA at the MRD Window - Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                     n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 129     45     NA      32      NA
ctDNA.MRD=POSITIVE  60     53   2.56       2     4.6
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30, 36))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     41      42    0.645  0.0456        0.548        0.726
   30     29       2    0.613  0.0486        0.511        0.700
   36     15       1    0.592  0.0513        0.484        0.684

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24      4      53    0.108  0.0409       0.0445        0.203
   30      3       0    0.108  0.0409       0.0445        0.203
   36      2       0    0.108  0.0409       0.0445        0.203
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 189, number of events= 98 

                    coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 1.7470    5.7371   0.2092 8.352   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     5.737     0.1743     3.808     8.645

Concordance= 0.701  (se = 0.021 )
Likelihood ratio test= 65.87  on 1 df,   p=5e-16
Wald test            = 69.75  on 1 df,   p=<2e-16
Score (logrank) test = 86.49  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 5.74 (3.81-8.64); p = 0"
#Fisher test for DFS percentages at 24, 30, and 36 months
dfs_times <- c(24, 30, 36)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months p-value at 36 months 
        2.248794e-13         8.823505e-13         1.412511e-12 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months Corrected p-value at 30 months Corrected p-value at 36 months 
                  6.746383e-13                   2.647051e-12                   4.237533e-12 

#OS by ctDNA at the MRD Window - Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$OS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                     n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 129      5     NA      NA      NA
ctDNA.MRD=POSITIVE  61     11   43.4      NA      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - ctDNA MRD window | All stages", ylab= "Overall Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30, 36))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     71       2    0.984  0.0111        0.938        0.996
   30     48       0    0.984  0.0111        0.938        0.996
   36     26       2    0.943  0.0306        0.841        0.980

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     23       7    0.836  0.0601        0.674        0.921
   30     12       3    0.717  0.0819        0.521        0.844
   36      6       0    0.717  0.0819        0.521        0.844
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 190, number of events= 16 

                    coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 1.8630    6.4429   0.5441 3.424 0.000618 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     6.443     0.1552     2.218     18.72

Concordance= 0.726  (se = 0.064 )
Likelihood ratio test= 12.93  on 1 df,   p=3e-04
Wald test            = 11.72  on 1 df,   p=6e-04
Score (logrank) test = 15.32  on 1 df,   p=9e-05
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 4))
print(label_text)
[1] "HR = 6.44 (2.22-18.72); p = 6e-04"
#Fisher test for OS percentages at 24, 30, and 36 months
os_times <- c(24, 30, 36)
p_values <- sapply(os_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.MRD.months >= time & circ_data$OS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.MRD.months >= time & circ_data$OS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.Event == 1 & circ_data$OS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.Event == 1 & circ_data$OS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", os_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months p-value at 36 months 
        0.0054510839         0.0002468767         0.0020570349 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", os_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months Corrected p-value at 30 months Corrected p-value at 36 months 
                  0.0163532517                   0.0007406301                   0.0061711046 

#Multivariate cox regression at MRD Window for DFS - Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"), labels = c("Right-sided", "Left-sided"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"), labels = c("Observation", "Chemotherapy"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.MRD + CEA.Baseline + Age.Group + PrimSite + NumLiverMetsGroup + SizeLiverMetsmmGroup + pT + pN + RAS + Mets.Type + Postop.Complication + Oxaliplatin.History, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Multivariate cox regression at MRD Window for DFS - ctDNA MRD Positive Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"), labels = c("Right-sided", "Left-sided"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"), labels = c("Observation", "Chemotherapy"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ CEA.Baseline + Age.Group + PrimSite + NumLiverMetsGroup + SizeLiverMetsmmGroup + pT + pN + RAS + Mets.Type + Postop.Complication + Oxaliplatin.History, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - ctDNA MRD Positive", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Multivariate cox regression at MRD Window for DFS - ctDNA MRD Negative Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"), labels = c("Right-sided", "Left-sided"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"), labels = c("Observation", "Chemotherapy"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
cox_fit <- coxph(surv_object ~ CEA.Baseline + Age.Group + PrimSite + NumLiverMetsGroup + SizeLiverMetsmmGroup + pT + pN + RAS + Mets.Type + Postop.Complication + Oxaliplatin.History, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - ctDNA MRD Negative", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#DFS by ACT treatment in MRD negative

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 92     33     NA    25.6      NA
ACT=TRUE  33      8     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      25.0000      31.0000       0.6222       0.0566       0.5011       0.7218 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      15.0000       8.0000       0.7231       0.0859       0.5143       0.8538 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 125, number of events= 41 

           coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.5575    1.7463   0.3948 1.412    0.158

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     1.746     0.5727    0.8054     3.786

Concordance= 0.553  (se = 0.032 )
Likelihood ratio test= 2.22  on 1 df,   p=0.1
Wald test            = 1.99  on 1 df,   p=0.2
Score (logrank) test = 2.05  on 1 df,   p=0.2
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.75 (0.81-3.79); p = 0.158"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
           0.3844277 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months 
                     0.3844277 
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + SizeLiverMetsmmGroup + RAS + Mets.Type + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + 
    SizeLiverMetsmmGroup + RAS + Mets.Type + Oxaliplatin.History, 
    data = circ_data)

  n= 125, number of events= 41 

                           coef exp(coef) se(coef)      z Pr(>|z|)
ACTTRUE                 -0.3844    0.6809   0.4300 -0.894    0.371
GenderMale               0.3311    1.3925   0.3938  0.841    0.400
Age.Group>70             0.2674    1.3066   0.3279  0.815    0.415
NumLiverMetsGroup≥2      0.2951    1.3432   0.3658  0.807    0.420
SizeLiverMetsmmGroup≥50  0.4474    1.5642   0.6244  0.716    0.474
RASMutant                0.3107    1.3644   0.3582  0.867    0.386
Mets.TypeSynchronous    -0.1946    0.8232   0.4471 -0.435    0.663
Oxaliplatin.HistoryYes   0.2572    1.2934   0.3778  0.681    0.496

                        exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                    0.6809     1.4687    0.2931     1.581
GenderMale                 1.3925     0.7181    0.6436     3.013
Age.Group>70               1.3066     0.7654    0.6871     2.485
NumLiverMetsGroup≥2        1.3432     0.7445    0.6559     2.751
SizeLiverMetsmmGroup≥50    1.5642     0.6393    0.4600     5.319
RASMutant                  1.3644     0.7329    0.6761     2.753
Mets.TypeSynchronous       0.8232     1.2148    0.3427     1.977
Oxaliplatin.HistoryYes     1.2934     0.7732    0.6168     2.712

Concordance= 0.638  (se = 0.042 )
Likelihood ratio test= 6.52  on 8 df,   p=0.6
Wald test            = 6.23  on 8 df,   p=0.6
Score (logrank) test = 6.37  on 8 df,   p=0.6

#DFS by ACT treatment in MRD positive

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 31     29   1.45    0.76    3.32
ACT=TRUE  15     10  12.92    4.11      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Positive ACT vs Observation", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     12.0000       3.0000      27.0000       0.1290       0.0602       0.0407       0.2698 

                ACT=TRUE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      9       6    0.600   0.126        0.318        0.797
   24      4       4    0.333   0.122        0.122        0.564
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 46, number of events= 39 

           coef exp(coef) se(coef)     z Pr(>|z|)    
ACTFALSE 1.3838    3.9899   0.3842 3.602 0.000316 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE      3.99     0.2506     1.879     8.472

Concordance= 0.675  (se = 0.03 )
Likelihood ratio test= 15  on 1 df,   p=1e-04
Wald test            = 12.97  on 1 df,   p=3e-04
Score (logrank) test = 14.61  on 1 df,   p=1e-04
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 3.99 (1.88-8.47); p = 0"
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + SizeLiverMetsmmGroup + RAS + Mets.Type + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + 
    SizeLiverMetsmmGroup + RAS + Mets.Type + Oxaliplatin.History, 
    data = circ_data)

  n= 46, number of events= 39 

                            coef exp(coef) se(coef)      z Pr(>|z|)    
ACTTRUE                 -2.68676   0.06810  0.67360 -3.989 6.65e-05 ***
GenderMale              -1.04107   0.35308  0.51890 -2.006  0.04483 *  
Age.Group>70            -0.01813   0.98203  0.39282 -0.046  0.96318    
NumLiverMetsGroup≥2     -0.94250   0.38965  0.43212 -2.181  0.02918 *  
SizeLiverMetsmmGroup≥50  1.96295   7.12027  0.91333  2.149  0.03162 *  
RASMutant                1.01046   2.74687  0.36487  2.769  0.00562 ** 
Mets.TypeSynchronous     0.62120   1.86116  0.44165  1.407  0.15956    
Oxaliplatin.HistoryYes   0.81261   2.25379  0.57133  1.422  0.15493    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                        exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                    0.0681    14.6840   0.01819    0.2550
GenderMale                 0.3531     2.8322   0.12770    0.9762
Age.Group>70               0.9820     1.0183   0.45473    2.1208
NumLiverMetsGroup≥2        0.3897     2.5664   0.16705    0.9089
SizeLiverMetsmmGroup≥50    7.1203     0.1404   1.18869   42.6504
RASMutant                  2.7469     0.3641   1.34357    5.6159
Mets.TypeSynchronous       1.8612     0.5373   0.78316    4.4230
Oxaliplatin.HistoryYes     2.2538     0.4437   0.73552    6.9061

Concordance= 0.785  (se = 0.033 )
Likelihood ratio test= 35.06  on 8 df,   p=3e-05
Wald test            = 28.56  on 8 df,   p=4e-04
Score (logrank) test = 35.96  on 8 df,   p=2e-05

#DFS by ACT treatment in MRD negative - Synchronous metastatic site

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$Mets.Type=="Synchronous",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 16      5     NA    9.01      NA
ACT=TRUE  17      3     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | Synchronous Met Site", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        5.000        5.000        0.661        0.125        0.364        0.844 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        9.000        3.000        0.776        0.116        0.447        0.924 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 33, number of events= 8 

           coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.8259    2.2838   0.7334 1.126     0.26

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     2.284     0.4379    0.5425     9.615

Concordance= 0.634  (se = 0.082 )
Likelihood ratio test= 1.32  on 1 df,   p=0.3
Wald test            = 1.27  on 1 df,   p=0.3
Score (logrank) test = 1.34  on 1 df,   p=0.2
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 2.28 (0.54-9.62); p = 0.26"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
           0.4384333 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months 
                     0.4384333 
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$Mets.Type=="Synchronous",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + 
    SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data = circ_data)

  n= 33, number of events= 8 

                           coef exp(coef) se(coef)      z Pr(>|z|)  
ACTTRUE                 -1.5633    0.2094   0.8370 -1.868   0.0618 .
GenderMale              -1.1347    0.3215   0.9708 -1.169   0.2425  
Age.Group>70            -0.6898    0.5017   0.8681 -0.795   0.4268  
NumLiverMetsGroup≥2      1.0846    2.9583   0.9082  1.194   0.2324  
SizeLiverMetsmmGroup≥50  1.7630    5.8302   1.3825  1.275   0.2022  
RASMutant                1.5951    4.9288   1.0234  1.559   0.1191  
Oxaliplatin.HistoryYes       NA        NA   0.0000     NA       NA  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                        exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                    0.2094     4.7744   0.04061     1.080
GenderMale                 0.3215     3.1102   0.04796     2.155
Age.Group>70               0.5017     1.9933   0.09151     2.750
NumLiverMetsGroup≥2        2.9583     0.3380   0.49889    17.543
SizeLiverMetsmmGroup≥50    5.8302     0.1715   0.38808    87.588
RASMutant                  4.9288     0.2029   0.66321    36.630
Oxaliplatin.HistoryYes         NA         NA        NA        NA

Concordance= 0.824  (se = 0.07 )
Likelihood ratio test= 10.15  on 6 df,   p=0.1
Wald test            = 7.56  on 6 df,   p=0.3
Score (logrank) test = 9.31  on 6 df,   p=0.2

#DFS by ACT treatment in MRD negative - Metachronous metastatic site

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$Mets.Type=="Metachronous",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 76     28     NA    25.6      NA
ACT=TRUE  16      5     NA    14.6      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | Metachronous Met Site", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      20.0000      26.0000       0.6142       0.0632       0.4784       0.7246 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        6.000        5.000        0.675        0.121        0.384        0.851 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 92, number of events= 33 

           coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.2494    1.2833   0.4859 0.513    0.608

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     1.283     0.7792    0.4951     3.326

Concordance= 0.514  (se = 0.033 )
Likelihood ratio test= 0.28  on 1 df,   p=0.6
Wald test            = 0.26  on 1 df,   p=0.6
Score (logrank) test = 0.26  on 1 df,   p=0.6
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.28 (0.5-3.33); p = 0.608"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
                   1 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months 
                             1 
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$Mets.Type=="Metachronous",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + NumLiverMetsGroup + 
    SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data = circ_data)

  n= 92, number of events= 33 

                            coef exp(coef) se(coef)      z Pr(>|z|)  
ACTTRUE                 -0.21989   0.80261  0.50394 -0.436   0.6626  
GenderMale               0.83345   2.30124  0.47385  1.759   0.0786 .
Age.Group>70             0.49048   1.63310  0.37182  1.319   0.1871  
NumLiverMetsGroup≥2      0.05637   1.05799  0.42226  0.133   0.8938  
SizeLiverMetsmmGroup≥50  0.39198   1.47990  0.75395  0.520   0.6031  
RASMutant                0.23766   1.26827  0.39924  0.595   0.5517  
Oxaliplatin.HistoryYes   0.41547   1.51508  0.39143  1.061   0.2885  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                        exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                    0.8026     1.2459    0.2989     2.155
GenderMale                 2.3012     0.4345    0.9091     5.825
Age.Group>70               1.6331     0.6123    0.7880     3.385
NumLiverMetsGroup≥2        1.0580     0.9452    0.4624     2.421
SizeLiverMetsmmGroup≥50    1.4799     0.6757    0.3377     6.486
RASMutant                  1.2683     0.7885    0.5799     2.774
Oxaliplatin.HistoryYes     1.5151     0.6600    0.7035     3.263

Concordance= 0.623  (se = 0.046 )
Likelihood ratio test= 6.09  on 7 df,   p=0.5
Wald test            = 5.71  on 7 df,   p=0.6
Score (logrank) test = 5.8  on 7 df,   p=0.6

#DFS by ACT treatment in MRD negative - 1 Liver Met

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$NumLiverMetsGroup=="1",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 69     22     NA      31      NA
ACT=TRUE  22      6     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | 1 Liver Met", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000       21.000       20.000        0.674        0.063        0.534        0.780 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000       11.000        6.000        0.693        0.107        0.434        0.851 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 91, number of events= 28 

           coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.3365    1.4000   0.4618 0.729    0.466

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE       1.4     0.7143    0.5663     3.461

Concordance= 0.536  (se = 0.038 )
Likelihood ratio test= 0.56  on 1 df,   p=0.5
Wald test            = 0.53  on 1 df,   p=0.5
Score (logrank) test = 0.54  on 1 df,   p=0.5
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.4 (0.57-3.46); p = 0.466"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
                   1 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months 
                             1 
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$NumLiverMetsGroup=="1",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Mets.Type + SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Mets.Type + 
    SizeLiverMetsmmGroup + RAS + Oxaliplatin.History, data = circ_data)

  n= 91, number of events= 28 

                            coef exp(coef) se(coef)      z Pr(>|z|)  
ACTTRUE                 -0.02522   0.97509  0.52282 -0.048   0.9615  
GenderMale               0.82189   2.27480  0.49890  1.647   0.0995 .
Age.Group>70             0.05878   1.06054  0.42162  0.139   0.8891  
Mets.TypeSynchronous    -0.38867   0.67796  0.55840 -0.696   0.4864  
SizeLiverMetsmmGroup≥50  1.26344   3.53757  0.63719  1.983   0.0474 *
RASMutant                0.82093   2.27261  0.45519  1.803   0.0713 .
Oxaliplatin.HistoryYes   0.25359   1.28864  0.50661  0.501   0.6167  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                        exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                    0.9751     1.0255    0.3500     2.717
GenderMale                 2.2748     0.4396    0.8556     6.048
Age.Group>70               1.0605     0.9429    0.4641     2.423
Mets.TypeSynchronous       0.6780     1.4750    0.2269     2.025
SizeLiverMetsmmGroup≥50    3.5376     0.2827    1.0147    12.333
RASMutant                  2.2726     0.4400    0.9312     5.546
Oxaliplatin.HistoryYes     1.2886     0.7760    0.4774     3.478

Concordance= 0.66  (se = 0.053 )
Likelihood ratio test= 8.34  on 7 df,   p=0.3
Wald test            = 9.02  on 7 df,   p=0.3
Score (logrank) test = 9.93  on 7 df,   p=0.2

#DFS by ACT treatment in MRD negative - 2≥ Liver Mets

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$NumLiverMetsGroup=="≥2",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE 23     11   20.3    6.15      NA
ACT=TRUE  11      2     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | ≥2 Liver Met", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        4.000       11.000        0.458        0.122        0.218        0.669 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        4.000        2.000        0.818        0.116        0.447        0.951 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 34, number of events= 13 

           coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 1.1484    3.1533   0.7692 1.493    0.135

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     3.153     0.3171    0.6983     14.24

Concordance= 0.602  (se = 0.062 )
Likelihood ratio test= 2.84  on 1 df,   p=0.09
Wald test            = 2.23  on 1 df,   p=0.1
Score (logrank) test = 2.48  on 1 df,   p=0.1
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 3.15 (0.7-14.24); p = 0.135"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
            0.139822 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months 
                      0.139822 
#Adjusted HR "ACT vs no ACT" - age, gender, ECOG and pathological stage - ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$NumLiverMetsGroup=="≥2",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Mets.Type + RAS + Oxaliplatin.History, data=circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Mets.Type + 
    RAS + Oxaliplatin.History, data = circ_data)

  n= 34, number of events= 13 

                            coef exp(coef)  se(coef)      z Pr(>|z|)
ACTTRUE                -1.350297  0.259163  0.833079 -1.621    0.105
GenderMale             -0.588374  0.555229  0.792352 -0.743    0.458
Age.Group>70            0.399882  1.491649  0.597240  0.670    0.503
Mets.TypeSynchronous   -0.006411  0.993610  0.794551 -0.008    0.994
RASMutant              -0.396021  0.672993  0.629514 -0.629    0.529
Oxaliplatin.HistoryYes  0.149209  1.160916  0.690752  0.216    0.829

                       exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE                   0.2592     3.8586   0.05064     1.326
GenderMale                0.5552     1.8011   0.11750     2.624
Age.Group>70              1.4916     0.6704   0.46269     4.809
Mets.TypeSynchronous      0.9936     1.0064   0.20936     4.716
RASMutant                 0.6730     1.4859   0.19596     2.311
Oxaliplatin.HistoryYes    1.1609     0.8614   0.29980     4.495

Concordance= 0.661  (se = 0.086 )
Likelihood ratio test= 4.56  on 6 df,   p=0.6
Wald test            = 3.86  on 6 df,   p=0.7
Score (logrank) test = 4.16  on 6 df,   p=0.7

#DFS by ctDNA Clearance ACT-treated at 3 months

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
survfit(Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   35 observations deleted due to missingness 
                 n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 8      4  14.00   13.80      NA
ctDNA.Dynamics=2 5      5   3.42    3.02      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 3 months ACT-treated", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(6, 12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

35 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6      7       1    0.875   0.117        0.387        0.981
   12      7       0    0.875   0.117        0.387        0.981
   24      3       3    0.500   0.177        0.152        0.775

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
       6.000        2.000        3.000        0.400        0.219        0.052        0.753 
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 13, number of events= 9 
   (35 observations deleted due to missingness)

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsNo Clearance  2.717    15.131    1.117 2.432    0.015 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     15.13    0.06609     1.695     135.1

Concordance= 0.736  (se = 0.053 )
Likelihood ratio test= 8.61  on 1 df,   p=0.003
Wald test            = 5.92  on 1 df,   p=0.02
Score (logrank) test = 9.83  on 1 df,   p=0.002
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 15.13 (1.69-135.08); p = 0.015"

#Levels of MRD MTM/mL in Clearance at 3 months log10 transformation

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Clearance <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Clearance = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
circ_data <- subset(circ_data, !is.na(ctDNA.Clearance))

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$ctDNA.Clearance <- factor(circ_data$ctDNA.Clearance, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
median_p_MRD_MTM <- aggregate(p_MRD_MTM ~ ctDNA.Clearance, data = circ_data, FUN = median)
print(median_p_MRD_MTM)

# Create violin plot with log10 scale on y-axis
ggplot(circ_data, aes(x=ctDNA.Clearance, y=p_MRD_MTM, fill=ctDNA.Clearance)) +
  geom_violin(trim=FALSE) +
  scale_fill_manual(values=c("Clearance"="lightblue", "No Clearance"="salmon")) +
  geom_boxplot(width=0.1, fill="white", colour="black", alpha=0.5) +
  scale_y_log10(breaks=c(0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000)) +
  labs(title="MRD MTM/mL | Clearance at 3 months", x="Clearance at 3 months", y="MRD MTM/mL") +
  theme_minimal() +
  theme(legend.position="none")

m3_1v2 <- wilcox.test(p_MRD_MTM ~ ctDNA.Clearance,
                      data = circ_data[circ_data$ctDNA.Clearance %in% c("Clearance", "No Clearance"), ],
                      na.rm = TRUE)
print(m3_1v2)

    Wilcoxon rank sum exact test

data:  p_MRD_MTM by ctDNA.Clearance
W = 13, p-value = 0.3543
alternative hypothesis: true location shift is not equal to 0

#DFS by ctDNA Clearance ACT-treated at 6 months

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   36 observations deleted due to missingness 
                 n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 9      5 11.696   9.429      NA
ctDNA.Dynamics=2 3      3  0.789   0.493      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 6 months ACT-treated", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(6, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

36 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6      7       2    0.778   0.139        0.365        0.939
   24      2       3    0.444   0.166        0.136        0.719

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     6.00000      1.00000      2.00000      0.33333      0.27217      0.00896      0.77415 
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 12, number of events= 8 
   (36 observations deleted due to missingness)

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsNo Clearance 1.9221    6.8355   0.9345 2.057   0.0397 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     6.836     0.1463     1.095     42.68

Concordance= 0.658  (se = 0.073 )
Likelihood ratio test= 4.19  on 1 df,   p=0.04
Wald test            = 4.23  on 1 df,   p=0.04
Score (logrank) test = 5.53  on 1 df,   p=0.02
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 6.84 (1.09-42.68); p = 0.04"

#Levels of MRD MTM/mL in Clearance at 6 months log10 transformation

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Clearance <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Clearance = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
circ_data <- subset(circ_data, !is.na(ctDNA.Clearance))

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$ctDNA.Clearance <- factor(circ_data$ctDNA.Clearance, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
median_p_MRD_MTM <- aggregate(p_MRD_MTM ~ ctDNA.Clearance, data = circ_data, FUN = median)
print(median_p_MRD_MTM)

# Create violin plot with log10 scale on y-axis
ggplot(circ_data, aes(x=ctDNA.Clearance, y=p_MRD_MTM, fill=ctDNA.Clearance)) +
  geom_violin(trim=FALSE) +
  scale_fill_manual(values=c("Clearance"="lightblue", "No Clearance"="salmon")) +
  geom_boxplot(width=0.1, fill="white", colour="black", alpha=0.5) +
  scale_y_log10(breaks=c(0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000)) +
  labs(title="MRD MTM/mL | Clearance at 6 months", x="Clearance at 6 months", y="MRD MTM/mL") +
  theme_minimal() +
  theme(legend.position="none")

m3_1v2 <- wilcox.test(p_MRD_MTM ~ ctDNA.Clearance,
                      data = circ_data[circ_data$ctDNA.Clearance %in% c("Clearance", "No Clearance"), ],
                      na.rm = TRUE)
print(m3_1v2)

    Wilcoxon rank sum exact test

data:  p_MRD_MTM by ctDNA.Clearance
W = 16, p-value = 0.7273
alternative hypothesis: true location shift is not equal to 0

#DFS by ctDNA at the Surveillance Window - Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ctDNA.Surveillance, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Surveillance, data = circ_data)

                             n events median 0.95LCL 0.95UCL
ctDNA.Surveillance=NEGATIVE 99     18     NA      NA      NA
ctDNA.Surveillance=POSITIVE 53     44   5.81    3.05    12.1
event_summary <- circ_data %>%
  group_by(ctDNA.Surveillance) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Surveillance, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Surveillance window", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30, 36))
Call: survfit(formula = surv_object ~ ctDNA.Surveillance, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Surveillance=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     41      16    0.815  0.0434        0.711        0.884
   30     31       1    0.795  0.0468        0.684        0.870
   36     15       1    0.768  0.0522        0.646        0.853

                ctDNA.Surveillance=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000       2.0000      44.0000       0.0859       0.0501       0.0200       0.2142 
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Surveillance, data = circ_data)

  n= 152, number of events= 62 

                              coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.SurveillancePOSITIVE  2.3644   10.6382   0.2982 7.929 2.21e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.SurveillancePOSITIVE     10.64      0.094      5.93     19.09

Concordance= 0.757  (se = 0.025 )
Likelihood ratio test= 73.09  on 1 df,   p=<2e-16
Wald test            = 62.87  on 1 df,   p=2e-15
Score (logrank) test = 91.54  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 10.64 (5.93-19.09); p = 0"
#Fisher test for DFS percentages at 24, 30, and 36 months
dfs_times <- c(24, 30, 36)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.Surveillance == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months p-value at 36 months 
        4.109654e-16         1.518274e-15         4.230750e-15 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", dfs_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months Corrected p-value at 30 months Corrected p-value at 36 months 
                  1.232896e-15                   4.554823e-15                   1.269225e-14 

#OS by ctDNA at the Surveillance Window - Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$OS.months=circ_data$OS.months-2.5
circ_data <- circ_data[circ_data$OS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~ctDNA.Surveillance, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    ctDNA.Surveillance, data = circ_data)

                             n events median 0.95LCL 0.95UCL
ctDNA.Surveillance=NEGATIVE 99      3     NA      NA      NA
ctDNA.Surveillance=POSITIVE 55      6   41.8    37.3      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Surveillance) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Surveillance, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - ctDNA Surveillance window", ylab= "Overall Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30, 36))
Call: survfit(formula = surv_object ~ ctDNA.Surveillance, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Surveillance=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     55       1    0.990  0.0104        0.928        0.999
   30     39       1    0.965  0.0259        0.855        0.992
   36     18       1    0.941  0.0351        0.817        0.982

                ctDNA.Surveillance=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     22       2    0.955  0.0319        0.827        0.989
   30     11       2    0.858  0.0715        0.641        0.948
   36      5       0    0.858  0.0715        0.641        0.948
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Surveillance, data = circ_data)

  n= 154, number of events= 9 

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.SurveillancePOSITIVE 1.6394    5.1523   0.7188 2.281   0.0226 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.SurveillancePOSITIVE     5.152     0.1941     1.259     21.08

Concordance= 0.678  (se = 0.094 )
Likelihood ratio test= 5.59  on 1 df,   p=0.02
Wald test            = 5.2  on 1 df,   p=0.02
Score (logrank) test = 6.33  on 1 df,   p=0.01
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 5.15 (1.26-21.08); p = 0.023"
#Fisher test for OS percentages at 24, 30, and 36 months
os_times <- c(24, 30, 36)
p_values <- sapply(os_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.months >= time & circ_data$OS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.months >= time & circ_data$OS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.Event == 1 & circ_data$OS.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.Event == 1 & circ_data$OS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", os_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months p-value at 36 months 
          0.12280702           0.02179403           0.04276279 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", os_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months Corrected p-value at 30 months Corrected p-value at 36 months 
                    0.36842105                     0.06538209                     0.12828838 

#Multivariate cox regression at Surveillance Window for DFS - Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$CEA.Baseline <- factor(circ_data$CEA.Baseline, levels=c("NEGATIVE","POSITIVE"), labels = c("Normal", "Elevated"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Right-sided colon", "Left-sided colon"), labels = c("Right-sided", "Left-sided"))
circ_data$NumLiverMetsGroup <- factor(circ_data$NumLiverMetsGroup, levels = c("1", "≥2"))
circ_data$SizeLiverMetsmmGroup <- factor(circ_data$SizeLiverMetsmmGroup, levels = c("<50", "≥50"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$ACT <- factor(circ_data$ACT, levels = c("FALSE", "TRUE"), labels = c("Observation", "Chemotherapy"))
circ_data$Postop.Complication <- factor(circ_data$Postop.Complication, levels = c("No", "Yes"))
circ_data$Oxaliplatin.History <- factor(circ_data$Oxaliplatin.History, levels = c("No", "Yes"))
circ_data$Mets.Type <- factor(circ_data$Mets.Type, levels = c("Metachronous", "Synchronous"))
circ_data$MSI <- factor(circ_data$MSI, levels = c("MSS", "MSI-High"), labels = c("MSS", "MSI-High"))
circ_data$BRAF.V600E <- factor(circ_data$BRAF.V600E, levels = c("WT", "MUT"), labels = c("Wild-Type", "V600E"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance + CEA.Baseline + Age.Group + PrimSite + NumLiverMetsGroup + SizeLiverMetsmmGroup + pT + pN + RAS + Mets.Type + Postop.Complication + Oxaliplatin.History, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#OS by ctDNA at the MRD Window - pts with Radiological Recurrence

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$OS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                    n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 42      2     NA      NA      NA
ctDNA.MRD=POSITIVE 53     10   43.4      NA      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.MRD.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - Radiological Recurrence | ctDNA MRD window", ylab= "Overall Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 36))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     25       0    1.000  0.0000           NA           NA
   36      8       1    0.933  0.0644        0.613         0.99

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     18       6     0.82  0.0709        0.627        0.919
   36      4       3     0.68  0.0942        0.459        0.827
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 95, number of events= 12 

                    coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.MRDPOSITIVE 1.8047    6.0781   0.7937 2.274    0.023 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     6.078     0.1645     1.283      28.8

Concordance= 0.735  (se = 0.031 )
Likelihood ratio test= 6.88  on 1 df,   p=0.009
Wald test            = 5.17  on 1 df,   p=0.02
Score (logrank) test = 6.56  on 1 df,   p=0.01
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 6.08 (1.28-28.8); p = 0.023"
#Fisher test for OS percentages at 24 and 36 months
os_times <- c(24, 36)
p_values <- sapply(os_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.MRD.months >= time & circ_data$OS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.MRD.months >= time & circ_data$OS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$OS.Event == 1 & circ_data$OS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$OS.Event == 1 & circ_data$OS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", os_times, " months")
print(p_values)
p-value at 24 months p-value at 36 months 
          0.03245083           0.03892912 
p_values_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_values_adjusted) <- paste0("Corrected p-value at ", os_times, " months")
print(p_values_adjusted)
Corrected p-value at 24 months Corrected p-value at 36 months 
                    0.06490165                     0.07785824 

#Percentage of ctDNA MRD Window positivity in pts with liver metastasis


rm(list = ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data %>%
  filter(LiverMets == "TRUE" & RFS.Event == "TRUE" & ctDNA.MRD != "")
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
positive_rate <- sum(circ_data$ctDNA.MRD == "Positive" & grepl("liver", circ_data$RelSite, ignore.case = TRUE)) / sum(circ_data$ctDNA.MRD == "Positive") * 100
positive_ci <- binconf(sum(circ_data$ctDNA.MRD == "Positive" & grepl("liver", circ_data$RelSite, ignore.case = TRUE)),
                       sum(circ_data$ctDNA.MRD == "Positive"),
                       alpha = 0.05)[c(2, 3)] * 100
negative_rate <- sum(circ_data$ctDNA.MRD == "Negative" & grepl("liver", circ_data$RelSite, ignore.case = TRUE)) / sum(circ_data$ctDNA.MRD == "Negative") * 100
negative_ci <- binconf(sum(circ_data$ctDNA.MRD == "Negative" & grepl("liver", circ_data$RelSite, ignore.case = TRUE)),
                       sum(circ_data$ctDNA.MRD == "Negative"),
                       alpha = 0.05)[c(2, 3)] * 100
data <- data.frame(
  ctDNA.MRD = c("Positive", "Negative"),
  percentage = c(positive_rate, negative_rate),
  lower_ci = c(positive_ci[1], negative_ci[1]),
  upper_ci = c(positive_ci[2], negative_ci[2])
)
cross_tabs <- list(
  table(circ_data$ctDNA.MRD, grepl("liver", circ_data$RelSite, ignore.case = TRUE)),
  table(circ_data$ctDNA.MRD, grepl("lung", circ_data$RelSite, ignore.case = TRUE))  # Example for another site
)
chi_tests <- lapply(cross_tabs, chisq.test)
p_values <- sapply(chi_tests, function(test) test$p.value)
num_tests <- length(p_values)  # Number of tests to be adjusted for
p_values_adjusted <- p.adjust(p_values, method = "bonferroni", n = num_tests)
print(data)
print(cross_tabs)
[[1]]
          
           FALSE TRUE
  Negative    28   14
  Positive    14   39

[[2]]
          
           FALSE TRUE
  Negative    16   26
  Positive    39   14
print(chi_tests)
[[1]]

    Pearson's Chi-squared test with Yates' continuity correction

data:  X[[i]]
X-squared = 13.803, df = 1, p-value = 0.000203


[[2]]

    Pearson's Chi-squared test with Yates' continuity correction

data:  X[[i]]
X-squared = 10.695, df = 1, p-value = 0.001074
print(paste("Original p-values:", format.pval(p_values, digits = 4)))
[1] "Original p-values: 0.0002" "Original p-values: 0.0011"
print(paste("Adjusted p-values (Bonferroni):", format.pval(p_values_adjusted, digits = 4)))
[1] "Adjusted p-values (Bonferroni): 0.0004" "Adjusted p-values (Bonferroni): 0.0021"
barplot <- ggplot(data, aes(x = ctDNA.MRD, y = percentage, fill = ctDNA.MRD)) +
  geom_bar(stat = "identity") +
  geom_errorbar(aes(ymin = lower_ci, ymax = upper_ci), width = 0.2) +
  geom_text(aes(label = paste0(round(percentage, 1), "%")), vjust = -0.5) +
  labs(
    x = "ctDNA status at the MRD status",
    y = "Proportion of patients with recurrence in the liver",
    caption = paste("Chi-squared test p-value: ", format.pval(p_values[1], digits = 4), 
                    "\nAdjusted p-value (Bonferroni): ", format.pval(p_values_adjusted[1], digits = 4))
  ) +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 100)) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) +
  theme_minimal()
print(barplot)

#Percentage of ctDNA MRD Window positivity in pts with lung metastasis

rm(list = ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data %>%
  filter(LiverMets == "TRUE" & RFS.Event == "TRUE" & ctDNA.MRD != "")
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
positive_rate <- sum(circ_data$ctDNA.MRD == "Positive" & grepl("lung", circ_data$RelSite, ignore.case = TRUE)) / sum(circ_data$ctDNA.MRD == "Positive") * 100
positive_ci <- binconf(sum(circ_data$ctDNA.MRD == "Positive" & grepl("lung", circ_data$RelSite, ignore.case = TRUE)),
                       sum(circ_data$ctDNA.MRD == "Positive"),
                       alpha = 0.05)[c(2, 3)] * 100
negative_rate <- sum(circ_data$ctDNA.MRD == "Negative" & grepl("lung", circ_data$RelSite, ignore.case = TRUE)) / sum(circ_data$ctDNA.MRD == "Negative") * 100
negative_ci <- binconf(sum(circ_data$ctDNA.MRD == "Negative" & grepl("lung", circ_data$RelSite, ignore.case = TRUE)),
                       sum(circ_data$ctDNA.MRD == "Negative"),
                       alpha = 0.05)[c(2, 3)] * 100
data <- data.frame(
  ctDNA.MRD = c("Positive", "Negative"),
  percentage = c(positive_rate, negative_rate),
  lower_ci = c(positive_ci[1], negative_ci[1]),
  upper_ci = c(positive_ci[2], negative_ci[2])
)

cross_tabs <- list(
  table(circ_data$ctDNA.MRD, grepl("lung", circ_data$RelSite, ignore.case = TRUE)),
  table(circ_data$ctDNA.MRD, grepl("liver", circ_data$RelSite, ignore.case = TRUE))
)
chi_tests <- lapply(cross_tabs, chisq.test)
p_values <- sapply(chi_tests, function(test) test$p.value)
num_tests <- length(p_values)  # Number of tests to be adjusted for
p_values_adjusted <- p.adjust(p_values, method = "bonferroni", n = num_tests)
print(data)
print(cross_tabs)
[[1]]
          
           FALSE TRUE
  Negative    16   26
  Positive    39   14

[[2]]
          
           FALSE TRUE
  Negative    28   14
  Positive    14   39
print(chi_tests)
[[1]]

    Pearson's Chi-squared test with Yates' continuity correction

data:  X[[i]]
X-squared = 10.695, df = 1, p-value = 0.001074


[[2]]

    Pearson's Chi-squared test with Yates' continuity correction

data:  X[[i]]
X-squared = 13.803, df = 1, p-value = 0.000203
print(paste("Original p-values:", format.pval(p_values, digits = 4)))
[1] "Original p-values: 0.0011" "Original p-values: 0.0002"
print(paste("Adjusted p-values (Bonferroni):", format.pval(p_values_adjusted, digits = 4)))
[1] "Adjusted p-values (Bonferroni): 0.0021" "Adjusted p-values (Bonferroni): 0.0004"
barplot <- ggplot(data, aes(x = ctDNA.MRD, y = percentage, fill = ctDNA.MRD)) +
  geom_bar(stat = "identity") +
  geom_errorbar(aes(ymin = lower_ci, ymax = upper_ci), width = 0.2) +
  geom_text(aes(label = paste0(round(percentage, 1), "%")), vjust = -0.5) +
  labs(
    x = "ctDNA status at the MRD status",
    y = "Proportion of patients with recurrence in the lung",
    caption = paste("Chi-squared test p-value: ", format.pval(p_values[1], digits = 4), 
                    "\nAdjusted p-value (Bonferroni): ", format.pval(p_values_adjusted[1], digits = 4))
  ) +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 100)) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) +
  theme_minimal()
print(barplot)

#Barplot with Recurrence Sites (Liver vs Others) by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Liver <- factor(circ_data$Liver, levels = c("FALSE", "TRUE"), labels = c("Others", "Liver"))
contingency_table <- table(circ_data$ctDNA.MRD, circ_data$Liver)
chi_square_test <- chisq.test(contingency_table)
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 18.352, df = 1, p-value = 1.836e-05
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 9.391e-06
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  2.744866 20.863460
sample estimates:
odds ratio 
  7.311049 
print(contingency_table)
          
           Others Liver
  Negative     30    12
  Positive     13    39
p_values <- c(chi_square_test$p.value, fisher_exact_test$p.value)
p_adjusted <- p.adjust(p_values, method = "bonferroni")
names(p_adjusted) <- c("Chi-Square Test", "Fisher's Exact Test")
print(p_adjusted)
    Chi-Square Test Fisher's Exact Test 
       3.672023e-05        1.878209e-05 
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Patients with Radiological Recurrence", 
       x = "ctDNA at the MRD Window", 
       y = "Patients (%)", 
       fill = "Recurrence Site",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value), "; Bonferroni corrected p-value: ", format.pval(p_adjusted["Chi-Square Test"]))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Others" = "blue", "Liver" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size

#Table with recurrence sites by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data_subset1 <- circ_data %>%
  select(
    Rec.Site) %>%
  mutate(
    Rec.Site = factor(Rec.Site, levels = c("Local/LN", "Liver", "Lung", "Peritoneum", "Peritoneum & Others", "Brain")))

circ_data1 <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data1 <- circ_data1[circ_data1$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data_subset2 <- circ_data %>%
  select(
    Rec.Site,
    ctDNA.MRD) %>%
  mutate(
    Rec.Site = factor(Rec.Site, levels = c("Local/LN", "Liver", "Lung", "Peritoneum", "Peritoneum & Others", "Brain")),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 951
Rec.Site
    Local/LN 4 (4.3%)
    Liver 48 (51%)
    Lung 30 (32%)
    Peritoneum 4 (4.3%)
    Peritoneum & Others 7 (7.4%)
    Brain 1 (1.1%)
    Unknown 1
1 n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # Subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p(test = all_categorical() ~ "fisher.test", pvalue_fun = ~style_pvalue(p.adjust(.x, method = "bonferroni"))) %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE, N = 421 POSITIVE, N = 531 p-value2
Rec.Site

<0.001
    Local/LN 1 (2.4%) 3 (5.8%)
    Liver 12 (29%) 36 (69%)
    Lung 23 (55%) 7 (13%)
    Peritoneum 3 (7.1%) 1 (1.9%)
    Peritoneum & Others 3 (7.1%) 4 (7.7%)
    Brain 0 (0%) 1 (1.9%)
    Unknown 0 1
1 n (%)
2 Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic Table 1 Table 2
N = 951 NEGATIVE, N = 421 POSITIVE, N = 531 p-value2
Rec.Site


<0.001
    Local/LN 4 (4.3%) 1 (2.4%) 3 (5.8%)
    Liver 48 (51%) 12 (29%) 36 (69%)
    Lung 30 (32%) 23 (55%) 7 (13%)
    Peritoneum 4 (4.3%) 3 (7.1%) 1 (1.9%)
    Peritoneum & Others 7 (7.4%) 3 (7.1%) 4 (7.7%)
    Brain 1 (1.1%) 0 (0%) 1 (1.9%)
    Unknown 1 0 1
1 n (%)
2 Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE,
  strip_md_bold = TRUE)
fit1

Table 1

Table 2

Characteristic

N = 951

NEGATIVE, N = 421

POSITIVE, N = 531

p-value2

Rec.Site

<0.001

Local/LN

4 (4.3%)

1 (2.4%)

3 (5.8%)

Liver

48 (51%)

12 (29%)

36 (69%)

Lung

30 (32%)

23 (55%)

7 (13%)

Peritoneum

4 (4.3%)

3 (7.1%)

1 (1.9%)

Peritoneum & Others

7 (7.4%)

3 (7.1%)

4 (7.7%)

Brain

1 (1.1%)

0 (0%)

1 (1.9%)

Unknown

1

0

1

1n (%)

2Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#Detection ctDNA rates based on sites of relapse

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Liver Mets Data_20240626 Complete Dataset.csv")
circ_data <- circ_data[circ_data$LiverMets=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]
circ_data <- subset(circ_data, !is.na(Rec.Site))

# Create a table of counts for the "Rec.Site" variable
relsite_counts <- table(circ_data$Rec.Site)
relsite_df <- as.data.frame(relsite_counts)
names(relsite_df) <- c("RelSite", "Count")
circ_data_pos_mrd <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data_pos_anytime <- circ_data[circ_data$ctDNA.anytime=="POSITIVE",]
pos_counts_mrd <- table(circ_data_pos_mrd$Rec.Site)
pos_counts_anytime <- table(circ_data_pos_anytime$Rec.Site)
relsite_df$MRDPos_Count <- ifelse(is.na(match(relsite_df$RelSite, names(pos_counts_mrd))), 0, pos_counts_mrd[match(relsite_df$RelSite, names(pos_counts_mrd))])
relsite_df$MRDPos_Count[is.na(relsite_df$MRDPos_Count)] <- 0
relsite_df$AnytimePos_Count <- ifelse(is.na(match(relsite_df$RelSite, names(pos_counts_anytime))), 0, pos_counts_anytime[match(relsite_df$RelSite, names(pos_counts_anytime))])
relsite_df$AnytimePos_Count[is.na(relsite_df$AnytimePos_Count)] <- 0
relsite_df$Percent <- (relsite_df$Count / sum(relsite_df$Count)) * 100
relsite_df$MRDPos_Percent <- (relsite_df$MRDPos_Count / relsite_df$Count) * 100
relsite_df$AnytimePos_Percent <- (relsite_df$AnytimePos_Count / relsite_df$Count) * 100
total_observations <- sum(relsite_df$Count)
total_pos_mrd <- sum(relsite_df$MRDPos_Count)
total_pos_anytime <- sum(relsite_df$AnytimePos_Count)
total_row <- data.frame(RelSite = "Total", Count = total_observations, MRDPos_Count = total_pos_mrd, AnytimePos_Count = total_pos_anytime, Percent = 100, MRDPos_Percent = (total_pos_mrd / total_observations) * 100, AnytimePos_Percent = (total_pos_anytime / total_observations) * 100)
relsite_df <- rbind(relsite_df, total_row)
print(relsite_df)

ft <- flextable(relsite_df)
doc <- read_docx() %>%
  body_add_flextable(value = ft)
print(doc, target = "relsite_df.docx")
LS0tCnRpdGxlOiAiR2FsYXh5IExpdmVyIE1ldHMgS2F0YW9rYSBldCBhbF8wODA1MjAyNCBDbGluaWNhbCBhbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKbGlicmFyeShzd2ltcGxvdCkKbGlicmFyeShjb3hwaGYpCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShndGFibGUpCmxpYnJhcnkocmVhZHIpIApsaWJyYXJ5KG1vc2FpYykKbGlicmFyeShkcGx5cikgCmxpYnJhcnkoc3Vydml2YWwpIApsaWJyYXJ5KHN1cnZtaW5lcikKbGlicmFyeShncmlkdGV4dCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShvZmZpY2VyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShndHN1bW1hcnkpCmxpYnJhcnkoZmxleHRhYmxlKQpsaWJyYXJ5KHBhcmFtZXRlcnMpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkocm1zKQpsaWJyYXJ5KERUKQoKI0RlbW9ncmFwaGljcyBUYWJsZQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCgpjaXJjX2RhdGFfc3Vic2V0IDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgUHJpbVNpdGUsCiAgICBNZXRzLlR5cGUsCiAgICBIZXBhdGVjdG9teSwKICAgIE51bUxpdmVyTWV0c0dyb3VwLAogICAgU2l6ZUxpdmVyTWV0c21tR3JvdXAsCiAgICBwVCwKICAgIHBOLAogICAgQUNULAogICAgT3hhbGlwbGF0aW4uSGlzdG9yeSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24sCiAgICBCUkFGLlY2MDBFLAogICAgUkFTLAogICAgTVNJLAogICAgUkZTLkV2ZW50LAogICAgT1MubW9udGhzKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBQcmltU2l0ZSA9IGZhY3RvcihQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKSwKICAgIE1ldHMuVHlwZSA9IGZhY3RvcihNZXRzLlR5cGUsIGxldmVscyA9IGMoIlN5bmNocm9ub3VzIiwgIk1ldGFjaHJvbm91cyIpKSwKICAgIEhlcGF0ZWN0b215ID0gZmFjdG9yKEhlcGF0ZWN0b215LCBsZXZlbHMgPSBjKCJNaW5vciIsICJNYWpvciIpKSwKICAgIE51bUxpdmVyTWV0c0dyb3VwID0gZmFjdG9yKE51bUxpdmVyTWV0c0dyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIuKJpTIiKSksCiAgICBTaXplTGl2ZXJNZXRzbW1Hcm91cCA9IGZhY3RvcihTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpLAogICAgcFQgPSBmYWN0b3IocFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpLAogICAgcE4gPSBmYWN0b3IocE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBPeGFsaXBsYXRpbi5IaXN0b3J5ID0gZmFjdG9yKE94YWxpcGxhdGluLkhpc3RvcnksIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24gPSBmYWN0b3IoUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpLAogICAgQlJBRi5WNjAwRSA9IGZhY3RvcihCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiQlJBRiB3dCIsICJCUkFGIFY2MDBFIikpLAogICAgUkFTID0gZmFjdG9yKFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIlJBUyB3dCIsICJSQVMgbXV0IikpLAogICAgTVNJID0gZmFjdG9yKE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpLAogICAgUkZTLkV2ZW50ID0gZmFjdG9yKFJGUy5FdmVudCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJSZWN1cnJlbmNlIiwgIk5vIFJlY3VycmVuY2UiKSksCiAgICBPUy5tb250aHMgPSBhcy5udW1lcmljKE9TLm1vbnRocykpCnRhYmxlMSA8LSBjaXJjX2RhdGFfc3Vic2V0ICU+JQogIHRibF9zdW1tYXJ5KAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGJvbGRfbGFiZWxzKCkKdGFibGUxCmZpdDEgPC0gYXNfZmxleF90YWJsZSgKICB0YWJsZTEsCiAgaW5jbHVkZSA9IGV2ZXJ5dGhpbmcoKSwKICByZXR1cm5fY2FsbHMgPSBGQUxTRSwKICBzdHJpcF9tZF9ib2xkID0gVFJVRSkKZml0MQpzYXZlX2FzX2RvY3goZml0MSwgcGF0aD0gIn4vRG93bmxvYWRzL3RhYmxlMS5kb2N4IikKYGBgCgoKI0RlbW9ncmFwaGljcyBUYWJsZSBieSBNUkQgY3RETkEgU3RhdHVzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KCmNpcmNfZGF0YV9zdWJzZXQxIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgUHJpbVNpdGUsCiAgICBNZXRzLlR5cGUsCiAgICBIZXBhdGVjdG9teSwKICAgIE51bUxpdmVyTWV0c0dyb3VwLAogICAgU2l6ZUxpdmVyTWV0c21tR3JvdXAsCiAgICBwVCwKICAgIHBOLAogICAgQUNULAogICAgT3hhbGlwbGF0aW4uSGlzdG9yeSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24sCiAgICBCUkFGLlY2MDBFLAogICAgUkFTLAogICAgTVNJKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBQcmltU2l0ZSA9IGZhY3RvcihQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKSwKICAgIE1ldHMuVHlwZSA9IGZhY3RvcihNZXRzLlR5cGUsIGxldmVscyA9IGMoIlN5bmNocm9ub3VzIiwgIk1ldGFjaHJvbm91cyIpKSwKICAgIEhlcGF0ZWN0b215ID0gZmFjdG9yKEhlcGF0ZWN0b215LCBsZXZlbHMgPSBjKCJNaW5vciIsICJNYWpvciIpKSwKICAgIE51bUxpdmVyTWV0c0dyb3VwID0gZmFjdG9yKE51bUxpdmVyTWV0c0dyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIuKJpTIiKSksCiAgICBTaXplTGl2ZXJNZXRzbW1Hcm91cCA9IGZhY3RvcihTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpLAogICAgcFQgPSBmYWN0b3IocFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpLAogICAgcE4gPSBmYWN0b3IocE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBPeGFsaXBsYXRpbi5IaXN0b3J5ID0gZmFjdG9yKE94YWxpcGxhdGluLkhpc3RvcnksIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24gPSBmYWN0b3IoUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpLAogICAgQlJBRi5WNjAwRSA9IGZhY3RvcihCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiQlJBRiB3dCIsICJCUkFGIFY2MDBFIikpLAogICAgUkFTID0gZmFjdG9yKFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIlJBUyB3dCIsICJSQVMgbXV0IikpLAogICAgTVNJID0gZmFjdG9yKE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpKQoKY2lyY19kYXRhMSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YTEgPC0gY2lyY19kYXRhMVtjaXJjX2RhdGExJExpdmVyTWV0cz09IlRSVUUiLF0KCmNpcmNfZGF0YV9zdWJzZXQyIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgUHJpbVNpdGUsCiAgICBNZXRzLlR5cGUsCiAgICBIZXBhdGVjdG9teSwKICAgIE51bUxpdmVyTWV0c0dyb3VwLAogICAgU2l6ZUxpdmVyTWV0c21tR3JvdXAsCiAgICBwVCwKICAgIHBOLAogICAgQUNULAogICAgT3hhbGlwbGF0aW4uSGlzdG9yeSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24sCiAgICBCUkFGLlY2MDBFLAogICAgUkFTLAogICAgTVNJLAogICAgY3RETkEuTVJEKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBQcmltU2l0ZSA9IGZhY3RvcihQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKSwKICAgIE1ldHMuVHlwZSA9IGZhY3RvcihNZXRzLlR5cGUsIGxldmVscyA9IGMoIlN5bmNocm9ub3VzIiwgIk1ldGFjaHJvbm91cyIpKSwKICAgIEhlcGF0ZWN0b215ID0gZmFjdG9yKEhlcGF0ZWN0b215LCBsZXZlbHMgPSBjKCJNaW5vciIsICJNYWpvciIpKSwKICAgIE51bUxpdmVyTWV0c0dyb3VwID0gZmFjdG9yKE51bUxpdmVyTWV0c0dyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIuKJpTIiKSksCiAgICBTaXplTGl2ZXJNZXRzbW1Hcm91cCA9IGZhY3RvcihTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpLAogICAgcFQgPSBmYWN0b3IocFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpLAogICAgcE4gPSBmYWN0b3IocE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBPeGFsaXBsYXRpbi5IaXN0b3J5ID0gZmFjdG9yKE94YWxpcGxhdGluLkhpc3RvcnksIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKSwKICAgIFBvc3RvcC5Db21wbGljYXRpb24gPSBmYWN0b3IoUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpLAogICAgQlJBRi5WNjAwRSA9IGZhY3RvcihCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiQlJBRiB3dCIsICJCUkFGIFY2MDBFIikpLAogICAgUkFTID0gZmFjdG9yKFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIlJBUyB3dCIsICJSQVMgbXV0IikpLAogICAgTVNJID0gZmFjdG9yKE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpLAogICAgY3RETkEuTVJEID0gZmFjdG9yKGN0RE5BLk1SRCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkpCk92ZXJhbGwgPC0gY2lyY19kYXRhX3N1YnNldDEgJT4lCiAgdGJsX3N1bW1hcnkoCiAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICBhbGxfY29udGludW91cygpIH4gInttZWRpYW59ICh7bWlufSAtIHttYXh9KSIsCiAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAoe3B9JSkiKSkgJT4lCiAgYm9sZF9sYWJlbHMoKQpPdmVyYWxsCgpCeWN0RE5BX01SRCA8LSBjaXJjX2RhdGFfc3Vic2V0MiAlPiUKICB0Ymxfc3VtbWFyeSgKICAgIGJ5ID0gY3RETkEuTVJELCAjIFN1Ymdyb3VwIGJ5IGN0RE5BLk1SRAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGFkZF9wKHRlc3QgPSBhbGxfY2F0ZWdvcmljYWwoKSB+ICJmaXNoZXIudGVzdCIsIHB2YWx1ZV9mdW4gPSB+c3R5bGVfcHZhbHVlKHAuYWRqdXN0KC54LCBtZXRob2QgPSAiYm9uZmVycm9uaSIpKSkgJT4lCiAgYm9sZF9sYWJlbHMoKQpCeWN0RE5BX01SRAoKbWVyZ2VkX3RhYmxlIDwtIHRibF9tZXJnZSh0YmxzPWxpc3QoT3ZlcmFsbCwgQnljdEROQV9NUkQpKQptZXJnZWRfdGFibGUKCmZpdDEgPC0gYXNfZmxleF90YWJsZSgKICBtZXJnZWRfdGFibGUsCiAgaW5jbHVkZSA9IGV2ZXJ5dGhpbmcoKSwKICByZXR1cm5fY2FsbHMgPSBGQUxTRSwKICBzdHJpcF9tZF9ib2xkID0gVFJVRSkKZml0MQpzYXZlX2FzX2RvY3goZml0MSwgcGF0aD0gIn4vRG93bmxvYWRzL21lcmdlZF90YWJsZS5kb2N4IikKYGBgCgojY3RETkEgRGV0ZWN0aW9uIFJhdGVzIGJ5IFdpbmRvdyBhbmQgU3RhZ2VzCmBgYHtyfQojY3RETkEgYXQgQmFzZWxpbmUKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lIT0iIixdCmNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjaXJjX2RhdGEkU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRTdGFnZSwgbGV2ZWxzPWMoIklWIikpCnBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUgPT0gIlBPU0lUSVZFIixdKQpvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSA8LSAob3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCAvIG92ZXJhbGxfdG90YWxfY291bnQpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQpvdmVyYWxsX3JvdyA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gIk92ZXJhbGwiLAogIFRvdGFsX0NvdW50ID0gb3ZlcmFsbF90b3RhbF9jb3VudCwKICBQb3NpdGl2ZV9Db3VudCA9IG92ZXJhbGxfcG9zaXRpdmVfY291bnQsCiAgUmF0ZSA9IHNwcmludGYoIiUuMmYlJSIsIG92ZXJhbGxfcG9zaXRpdml0eV9yYXRlKQopCmNvbWJpbmVkX2RhdGEgPC0gcmJpbmQoY29tYmluZWRfZGF0YSwgb3ZlcmFsbF9yb3cpCnByaW50KGNvbWJpbmVkX2RhdGEpCgojY3RETkEgYXQgTVJEIFdpbmRvdwpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRTdGFnZSA8LSBmYWN0b3IoY2lyY19kYXRhJFN0YWdlLCBsZXZlbHM9YygiSVYiKSkKcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuTVJELCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSRHcm91cC4xLAogIFRvdGFsX0NvdW50ID0gdG90YWxfY291bnRzX2J5X3N0YWdlJHgsCiAgUG9zaXRpdmVfQ291bnQgPSBwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCwKICBSYXRlID0gKHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4IC8gdG90YWxfY291bnRzX2J5X3N0YWdlJHgpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQopCmNvbWJpbmVkX2RhdGEkUmF0ZSA8LSBzcHJpbnRmKCIlLjJmJSUiLCBjb21iaW5lZF9kYXRhJFJhdGUpCm92ZXJhbGxfdG90YWxfY291bnQgPC0gbnJvdyhjaXJjX2RhdGEpCm92ZXJhbGxfcG9zaXRpdmVfY291bnQgPC0gbnJvdyhjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiLF0pCm92ZXJhbGxfcG9zaXRpdml0eV9yYXRlIDwtIChvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IC8gb3ZlcmFsbF90b3RhbF9jb3VudCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCm92ZXJhbGxfcm93IDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKCiNjdEROQSBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjaXJjX2RhdGEgPC0gc3Vic2V0KGNpcmNfZGF0YSwgY3RETkEuU3VydmVpbGxhbmNlICVpbiUgYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscz1jKCJJViIpKQpwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIiwgYnk9bGlzdChjaXJjX2RhdGEkU3RhZ2UpLCBGVU49c3VtKQp0b3RhbF9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIsXSkKb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUgPC0gKG92ZXJhbGxfcG9zaXRpdmVfY291bnQgLyBvdmVyYWxsX3RvdGFsX2NvdW50KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKb3ZlcmFsbF9yb3cgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9ICJPdmVyYWxsIiwKICBUb3RhbF9Db3VudCA9IG92ZXJhbGxfdG90YWxfY291bnQsCiAgUG9zaXRpdmVfQ291bnQgPSBvdmVyYWxsX3Bvc2l0aXZlX2NvdW50LAogIFJhdGUgPSBzcHJpbnRmKCIlLjJmJSUiLCBvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSkKKQpjb21iaW5lZF9kYXRhIDwtIHJiaW5kKGNvbWJpbmVkX2RhdGEsIG92ZXJhbGxfcm93KQpwcmludChjb21iaW5lZF9kYXRhKQpgYGAKCgoKI2N0RE5BIERldGVjdGlvbiBSYXRlcyBieSBXaW5kb3cgYW5kIFN5bmNocm9uaWNpdHkKYGBge3J9CiNjdEROQSBhdCBCYXNlbGluZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUhPSIiLF0KY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSA9PSAiUE9TSVRJVkUiLCBieT1saXN0KGNpcmNfZGF0YSRNZXRzLlR5cGUpLCBGVU49c3VtKQp0b3RhbF9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSwgYnk9bGlzdChjaXJjX2RhdGEkTWV0cy5UeXBlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUgPT0gIlBPU0lUSVZFIixdKQpvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSA8LSAob3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCAvIG92ZXJhbGxfdG90YWxfY291bnQpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQpvdmVyYWxsX3JvdyA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gIk92ZXJhbGwiLAogIFRvdGFsX0NvdW50ID0gb3ZlcmFsbF90b3RhbF9jb3VudCwKICBQb3NpdGl2ZV9Db3VudCA9IG92ZXJhbGxfcG9zaXRpdmVfY291bnQsCiAgUmF0ZSA9IHNwcmludGYoIiUuMmYlJSIsIG92ZXJhbGxfcG9zaXRpdml0eV9yYXRlKQopCmNvbWJpbmVkX2RhdGEgPC0gcmJpbmQoY29tYmluZWRfZGF0YSwgb3ZlcmFsbF9yb3cpCnByaW50KGNvbWJpbmVkX2RhdGEpCgojY3RETkEgYXQgTVJEIFdpbmRvdwpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiwgYnk9bGlzdChjaXJjX2RhdGEkTWV0cy5UeXBlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuTVJELCBieT1saXN0KGNpcmNfZGF0YSRNZXRzLlR5cGUpLCBGVU49bGVuZ3RoKQpjb21iaW5lZF9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgTWV0cy5UeXBlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIsXSkKb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUgPC0gKG92ZXJhbGxfcG9zaXRpdmVfY291bnQgLyBvdmVyYWxsX3RvdGFsX2NvdW50KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKb3ZlcmFsbF9yb3cgPC0gZGF0YS5mcmFtZSgKICBNZXRzLlR5cGUgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKCiNjdEROQSBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjaXJjX2RhdGEgPC0gc3Vic2V0KGNpcmNfZGF0YSwgY3RETkEuU3VydmVpbGxhbmNlICVpbiUgYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCnBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiUE9TSVRJVkUiLCBieT1saXN0KGNpcmNfZGF0YSRNZXRzLlR5cGUpLCBGVU49c3VtKQp0b3RhbF9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGJ5PWxpc3QoY2lyY19kYXRhJE1ldHMuVHlwZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBNZXRzLlR5cGUgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkR3JvdXAuMSwKICBUb3RhbF9Db3VudCA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSR4LAogIFBvc2l0aXZlX0NvdW50ID0gcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHgsCiAgUmF0ZSA9IChwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCAvIHRvdGFsX2NvdW50c19ieV9zdGFnZSR4KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKKQpjb21iaW5lZF9kYXRhJFJhdGUgPC0gc3ByaW50ZigiJS4yZiUlIiwgY29tYmluZWRfZGF0YSRSYXRlKQpvdmVyYWxsX3RvdGFsX2NvdW50IDwtIG5yb3coY2lyY19kYXRhKQpvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IDwtIG5yb3coY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIixdKQpvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSA8LSAob3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCAvIG92ZXJhbGxfdG90YWxfY291bnQpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQpvdmVyYWxsX3JvdyA8LSBkYXRhLmZyYW1lKAogIE1ldHMuVHlwZSA9ICJPdmVyYWxsIiwKICBUb3RhbF9Db3VudCA9IG92ZXJhbGxfdG90YWxfY291bnQsCiAgUG9zaXRpdmVfQ291bnQgPSBvdmVyYWxsX3Bvc2l0aXZlX2NvdW50LAogIFJhdGUgPSBzcHJpbnRmKCIlLjJmJSUiLCBvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSkKKQpjb21iaW5lZF9kYXRhIDwtIHJiaW5kKGNvbWJpbmVkX2RhdGEsIG92ZXJhbGxfcm93KQpwcmludChjb21iaW5lZF9kYXRhKQpgYGAKCgoKI0JhcnBsb3Qgd2l0aCBEZXRlY3Rpb24gUmF0ZXMgYXQgdGhlIE1SRCBhbmQgU3VydmVpbGxhbmNlIFdpbmRvd3MgYnkgU3luY2hyb25pY2l0eQpgYGB7cn0KI0RldGVjdGlvbiByYXRlIGF0IHRoZSBTdXJ2ZWlsbGFuY2UgV2luZG93CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQoKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGNpcmNfZGF0YSRjdEROQS5NUkQpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmZpc2hlcl9leGFjdF90ZXN0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChmaXNoZXJfZXhhY3RfdGVzdCkKcHJpbnQoY29udGluZ2VuY3lfdGFibGUpCnBfdmFsdWVzIDwtIGMoY2hpX3NxdWFyZV90ZXN0JHAudmFsdWUsIGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpCnBfYWRqdXN0ZWQgPC0gcC5hZGp1c3QocF92YWx1ZXMsIG1ldGhvZCA9ICJib25mZXJyb25pIikKbmFtZXMocF9hZGp1c3RlZCkgPC0gYygiQ2hpLVNxdWFyZSBUZXN0IiwgIkZpc2hlcidzIEV4YWN0IFRlc3QiKQpwcmludChwX2FkanVzdGVkKQp0YWJsZV9kZiA8LSBhcy5kYXRhLmZyYW1lKGNvbnRpbmdlbmN5X3RhYmxlKQp0YWJsZV9kZiRUb3RhbCA8LSBhdmUodGFibGVfZGYkRnJlcSwgdGFibGVfZGYkVmFyMSwgRlVOID0gc3VtKQp0YWJsZV9kZiRQZXJjZW50YWdlIDwtIHRhYmxlX2RmJEZyZXEgLyB0YWJsZV9kZiRUb3RhbAp0YWJsZV9kZiRNaWRkbGVQZXJjZW50YWdlIDwtIHRhYmxlX2RmJFBlcmNlbnRhZ2UgLyAyCmdncGxvdCh0YWJsZV9kZiwgYWVzKHggPSBWYXIxLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IFZhcjIpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKHkgPSBNaWRkbGVQZXJjZW50YWdlLCBsYWJlbCA9IEZyZXEpLCBwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIiwgdmp1c3QgPSAxLjUsIHNpemUgPSA3KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlBhdGllbnRzIHdpdGggQ0xNIC0gY3RETkEgTVJEIFdpbmRvdyIsIAogICAgICAgeCA9ICJTeW5jaHJvbmljaXR5IiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJjdEROQSBNUkQgV2luZG93IiwKICAgICAgIGNhcHRpb24gPSBwYXN0ZSgiQ2hpLXNxdWFyZWQgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSksICI7IEJvbmZlcnJvbmkgY29ycmVjdGVkIHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKHBfYWRqdXN0ZWRbIkNoaS1TcXVhcmUgVGVzdCJdKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTmVnYXRpdmUiID0gImJsdWUiLCAiUG9zaXRpdmUiID0gInJlZCIpKSArICMgZGVmaW5lIGN1c3RvbSBjb2xvcnMKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMS41LCBzaXplID0gMTQpLCAjIGluY3JlYXNlIHgtYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeC1heGlzIGxhYmVsIHNpemUKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyBsYWJlbCBzaXplCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpKSAgIyBpbmNyZWFzZSBSZWN1cnJlbmNlIGxhYmVsIHNpemUKCiNEZXRlY3Rpb24gcmF0ZSBhdCB0aGUgU3VydmVpbGxhbmNlIFdpbmRvdwpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KCmNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkTWV0cy5UeXBlLCBjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlKQpjaGlfc3F1YXJlX3Rlc3QgPC0gY2hpc3EudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoY2hpX3NxdWFyZV90ZXN0KQpmaXNoZXJfZXhhY3RfdGVzdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoZmlzaGVyX2V4YWN0X3Rlc3QpCnByaW50KGNvbnRpbmdlbmN5X3RhYmxlKQpwX3ZhbHVlcyA8LSBjKGNoaV9zcXVhcmVfdGVzdCRwLnZhbHVlLCBmaXNoZXJfZXhhY3RfdGVzdCRwLnZhbHVlKQpwX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCm5hbWVzKHBfYWRqdXN0ZWQpIDwtIGMoIkNoaS1TcXVhcmUgVGVzdCIsICJGaXNoZXIncyBFeGFjdCBUZXN0IikKcHJpbnQocF9hZGp1c3RlZCkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJQYXRpZW50cyB3aXRoIENMTSAtIGN0RE5BIFN1cnZlaWxsYW5jZSBXaW5kb3ciLCAKICAgICAgIHggPSAiU3luY2hyb25pY2l0eSIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiY3RETkEgU3VydmVpbGxhbmNlIFdpbmRvdyIsCiAgICAgICBjYXB0aW9uID0gcGFzdGUoIkNoaS1zcXVhcmVkIHRlc3QgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwoY2hpX3NxdWFyZV90ZXN0JHAudmFsdWUpLCAiOyBCb25mZXJyb25pIGNvcnJlY3RlZCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChwX2FkanVzdGVkWyJDaGktU3F1YXJlIFRlc3QiXSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5lZ2F0aXZlIiA9ICJibHVlIiwgIlBvc2l0aXZlIiA9ICJyZWQiKSkgKyAjIGRlZmluZSBjdXN0b20gY29sb3JzCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEuNSwgc2l6ZSA9IDE0KSwgIyBpbmNyZWFzZSB4LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHgtYXhpcyBsYWJlbCBzaXplCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSkgICMgaW5jcmVhc2UgUmVjdXJyZW5jZSBsYWJlbCBzaXplCmBgYAoKI0JhcnBsb3Qgd2l0aCBEZXRlY3Rpb24gUmF0ZXMgYXQgcHJlLW9wIGFuZCBjdEROQSBNUkQgYnkgcHJlLU9QIENFQQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCgpjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENFQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTm9ybWFsIiwgIkVsZXZhdGVkIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRDRUEuQmFzZWxpbmUsIGNpcmNfZGF0YSRjdEROQS5CYXNlbGluZSkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKcF92YWx1ZXMgPC0gYyhjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSwgZmlzaGVyX2V4YWN0X3Rlc3QkcC52YWx1ZSkKcF9hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX2FkanVzdGVkKSA8LSBjKCJDaGktU3F1YXJlIFRlc3QiLCAiRmlzaGVyJ3MgRXhhY3QgVGVzdCIpCnByaW50KHBfYWRqdXN0ZWQpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiUHJlLW9wIENFQSAmIFByZS1vcCBjdEROQSIsIAogICAgICAgeCA9ICJQcmUtb3AgQ0VBIiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJjdEROQSBwcmUtb3AiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJDaGktc3F1YXJlZCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGNoaV9zcXVhcmVfdGVzdCRwLnZhbHVlKSwgIjsgQm9uZmVycm9uaSBjb3JyZWN0ZWQgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwocF9hZGp1c3RlZFsiQ2hpLVNxdWFyZSBUZXN0Il0pKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOZWdhdGl2ZSIgPSAiYmx1ZSIsICJQb3NpdGl2ZSIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFJlY3VycmVuY2UgbGFiZWwgc2l6ZQoKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCgpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpLCBsYWJlbHMgPSBjKCJOZWdhdGl2ZSIsICJQb3NpdGl2ZSIpKQpjaXJjX2RhdGEkQ0VBLkJhc2VsaW5lIDwtIGZhY3RvcihjaXJjX2RhdGEkQ0VBLkJhc2VsaW5lLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpLCBsYWJlbHMgPSBjKCJOb3JtYWwiLCAiRWxldmF0ZWQiKSkKY29udGluZ2VuY3lfdGFibGUgPC0gdGFibGUoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgY2lyY19kYXRhJGN0RE5BLk1SRCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKcF92YWx1ZXMgPC0gYyhjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSwgZmlzaGVyX2V4YWN0X3Rlc3QkcC52YWx1ZSkKcF9hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX2FkanVzdGVkKSA8LSBjKCJDaGktU3F1YXJlIFRlc3QiLCAiRmlzaGVyJ3MgRXhhY3QgVGVzdCIpCnByaW50KHBfYWRqdXN0ZWQpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiUHJlLW9wIENFQSAmIGN0RE5BIE1SRCIsIAogICAgICAgeCA9ICJQcmUtb3AgQ0VBIiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJjdEROQSBhdCBNUkQiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJDaGktc3F1YXJlZCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGNoaV9zcXVhcmVfdGVzdCRwLnZhbHVlKSwgIjsgQm9uZmVycm9uaSBjb3JyZWN0ZWQgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwocF9hZGp1c3RlZFsiQ2hpLVNxdWFyZSBUZXN0Il0pKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOZWdhdGl2ZSIgPSAiYmx1ZSIsICJQb3NpdGl2ZSIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFJlY3VycmVuY2UgbGFiZWwgc2l6ZQpgYGAKCiNERlMgYnkgY3RETkEgYXQgdGhlIE1SRCBXaW5kb3cgLSBMYW5kbWFyayBNUkQgdGltZXBvaW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5NUkQsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLk1SRCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgd2luZG93IiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCwgMzAsIDM2KSkKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMjQsIDMwLCBhbmQgMzYgbW9udGhzCmRmc190aW1lcyA8LSBjKDI0LCAzMCwgMzYpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgpwX3ZhbHVlc19hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX3ZhbHVlc19hZGp1c3RlZCkgPC0gcGFzdGUwKCJDb3JyZWN0ZWQgcC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXNfYWRqdXN0ZWQpCmBgYAoKCgoKI09TIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93IC0gTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRPUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKE9TLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iT1MgLSBjdEROQSBNUkQgd2luZG93IHwgQWxsIHN0YWdlcyIsIHlsYWI9ICJPdmVyYWxsIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0LCAzMCwgMzYpKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgNCkpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIE9TIHBlcmNlbnRhZ2VzIGF0IDI0LCAzMCwgYW5kIDM2IG1vbnRocwpvc190aW1lcyA8LSBjKDI0LCAzMCwgMzYpCnBfdmFsdWVzIDwtIHNhcHBseShvc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJE9TLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRPUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJE9TLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRPUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkT1MuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRPUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJE9TLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkT1MuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBvc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCnBfdmFsdWVzX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCm5hbWVzKHBfdmFsdWVzX2FkanVzdGVkKSA8LSBwYXN0ZTAoIkNvcnJlY3RlZCBwLXZhbHVlIGF0ICIsIG9zX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzX2FkanVzdGVkKQpgYGAKCgoKCiNNdWx0aXZhcmlhdGUgY294IHJlZ3Jlc3Npb24gYXQgTVJEIFdpbmRvdyBmb3IgREZTIC0gTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENFQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTm9ybWFsIiwgIkVsZXZhdGVkIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJSaWdodC1zaWRlZCBjb2xvbiIsICJMZWZ0LXNpZGVkIGNvbG9uIiksIGxhYmVscyA9IGMoIlJpZ2h0LXNpZGVkIiwgIkxlZnQtc2lkZWQiKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJPYnNlcnZhdGlvbiIsICJDaGVtb3RoZXJhcHkiKSkKY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uLCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnkgPC0gZmFjdG9yKGNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5LCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNpcmNfZGF0YSRNU0kgPC0gZmFjdG9yKGNpcmNfZGF0YSRNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpLCBsYWJlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSkKY2lyY19kYXRhJEJSQUYuVjYwMEUgPC0gZmFjdG9yKGNpcmNfZGF0YSRCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIlY2MDBFIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCArIENFQS5CYXNlbGluZSArIEFnZS5Hcm91cCArIFByaW1TaXRlICsgTnVtTGl2ZXJNZXRzR3JvdXAgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIHBUICsgcE4gKyBSQVMgKyBNZXRzLlR5cGUgKyBQb3N0b3AuQ29tcGxpY2F0aW9uICsgT3hhbGlwbGF0aW4uSGlzdG9yeSwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBERlMiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBhdCBNUkQgV2luZG93IGZvciBERlMgLSBjdEROQSBNUkQgUG9zaXRpdmUgTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09IlBPU0lUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJENFQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTm9ybWFsIiwgIkVsZXZhdGVkIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJSaWdodC1zaWRlZCBjb2xvbiIsICJMZWZ0LXNpZGVkIGNvbG9uIiksIGxhYmVscyA9IGMoIlJpZ2h0LXNpZGVkIiwgIkxlZnQtc2lkZWQiKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJPYnNlcnZhdGlvbiIsICJDaGVtb3RoZXJhcHkiKSkKY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uLCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnkgPC0gZmFjdG9yKGNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5LCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNpcmNfZGF0YSRNU0kgPC0gZmFjdG9yKGNpcmNfZGF0YSRNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpLCBsYWJlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSkKY2lyY19kYXRhJEJSQUYuVjYwMEUgPC0gZmFjdG9yKGNpcmNfZGF0YSRCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIlY2MDBFIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IENFQS5CYXNlbGluZSArIEFnZS5Hcm91cCArIFByaW1TaXRlICsgTnVtTGl2ZXJNZXRzR3JvdXAgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIHBUICsgcE4gKyBSQVMgKyBNZXRzLlR5cGUgKyBQb3N0b3AuQ29tcGxpY2F0aW9uICsgT3hhbGlwbGF0aW4uSGlzdG9yeSwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBERlMgLSBjdEROQSBNUkQgUG9zaXRpdmUiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBhdCBNUkQgV2luZG93IGZvciBERlMgLSBjdEROQSBNUkQgTmVnYXRpdmUgTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJENFQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTm9ybWFsIiwgIkVsZXZhdGVkIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJSaWdodC1zaWRlZCBjb2xvbiIsICJMZWZ0LXNpZGVkIGNvbG9uIiksIGxhYmVscyA9IGMoIlJpZ2h0LXNpZGVkIiwgIkxlZnQtc2lkZWQiKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJPYnNlcnZhdGlvbiIsICJDaGVtb3RoZXJhcHkiKSkKY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uLCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnkgPC0gZmFjdG9yKGNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5LCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNpcmNfZGF0YSRNU0kgPC0gZmFjdG9yKGNpcmNfZGF0YSRNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpLCBsYWJlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSkKY2lyY19kYXRhJEJSQUYuVjYwMEUgPC0gZmFjdG9yKGNpcmNfZGF0YSRCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIlY2MDBFIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gQ0VBLkJhc2VsaW5lICsgQWdlLkdyb3VwICsgUHJpbVNpdGUgKyBOdW1MaXZlck1ldHNHcm91cCArIFNpemVMaXZlck1ldHNtbUdyb3VwICsgcFQgKyBwTiArIFJBUyArIE1ldHMuVHlwZSArIFBvc3RvcC5Db21wbGljYXRpb24gKyBPeGFsaXBsYXRpbi5IaXN0b3J5LCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsIGRhdGEgPSBjaXJjX2RhdGEsIG1haW4gPSAiTXVsdGl2YXJpYXRlIFJlZ3Jlc3Npb24gTW9kZWwgZm9yIERGUyAtIGN0RE5BIE1SRCBOZWdhdGl2ZSIsIHJlZkxhYmVsID0gIlJlZmVyZW5jZSBHcm91cCIpCnRlc3QucGggPC0gY294LnpwaChjb3hfZml0KQpgYGAKCgojREZTIGJ5IEFDVCB0cmVhdG1lbnQgaW4gTVJEIG5lZ2F0aXZlCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5BQ1QsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KEFDVCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoInJlZCIsImJsdWUiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBOZWdhdGl2ZSBBQ1QgdnMgT2JzZXJ2YXRpb24iLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJPYnNlcnZhdGlvbiIsICJBQ1QiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCkpCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscz1jKCJUUlVFIiwiRkFMU0UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMjQKZGZzX3RpbWVzIDwtIGMoMjQpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCnBfdmFsdWVzX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCm5hbWVzKHBfdmFsdWVzX2FkanVzdGVkKSA8LSBwYXN0ZTAoIkNvcnJlY3RlZCBwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlc19hZGp1c3RlZCkKCiNBZGp1c3RlZCBIUiAiQUNUIHZzIG5vIEFDVCIgLSBhZ2UsIGdlbmRlciwgRUNPRyBhbmQgcGF0aG9sb2dpY2FsIHN0YWdlIC0gQUNUIGFzIHJlZmVyZW5jZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJEdlbmRlciA8LSBmYWN0b3IoY2lyY19kYXRhJEdlbmRlciwgbGV2ZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkKY2lyY19kYXRhJEFnZS5Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJEFnZS5Hcm91cCwgbGV2ZWxzID0gYygiMSIsICIyIiksIGxhYmVscyA9IGMoIjw3MCIsICI+NzAiKSkKY2lyY19kYXRhJFByaW1TaXRlIDwtIGZhY3RvcihjaXJjX2RhdGEkUHJpbVNpdGUsIGxldmVscyA9IGMoIlJpZ2h0LXNpZGVkIGNvbG9uIiwgIkxlZnQtc2lkZWQgY29sb24iKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpKQpjaXJjX2RhdGEkUG9zdG9wLkNvbXBsaWNhdGlvbiA8LSBmYWN0b3IoY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24sIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKQpjaXJjX2RhdGEkT3hhbGlwbGF0aW4uSGlzdG9yeSA8LSBmYWN0b3IoY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnksIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKQpjaXJjX2RhdGEkTWV0cy5UeXBlIDwtIGZhY3RvcihjaXJjX2RhdGEkTWV0cy5UeXBlLCBsZXZlbHMgPSBjKCJNZXRhY2hyb25vdXMiLCAiU3luY2hyb25vdXMiKSkKY2lyY19kYXRhJE1TSSA8LSBmYWN0b3IoY2lyY19kYXRhJE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIiksIGxhYmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpKQpjaXJjX2RhdGEkQlJBRi5WNjAwRSA8LSBmYWN0b3IoY2lyY19kYXRhJEJSQUYuVjYwMEUsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiVjYwMEUiKSkKY2lyY19kYXRhJFJBUyA8LSBmYWN0b3IoY2lyY19kYXRhJFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIldpbGQtVHlwZSIsICJNdXRhbnQiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gQUNUICsgR2VuZGVyICsgQWdlLkdyb3VwICsgTnVtTGl2ZXJNZXRzR3JvdXAgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIFJBUyArIE1ldHMuVHlwZSArIE94YWxpcGxhdGluLkhpc3RvcnksIGRhdGE9Y2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojREZTIGJ5IEFDVCB0cmVhdG1lbnQgaW4gTVJEIHBvc2l0aXZlCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09IlBPU0lUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5BQ1QsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KEFDVCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoInJlZCIsImJsdWUiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBQb3NpdGl2ZSBBQ1QgdnMgT2JzZXJ2YXRpb24iLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJPYnNlcnZhdGlvbiIsICJBQ1QiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiVFJVRSIsIkZBTFNFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNBZGp1c3RlZCBIUiAiQUNUIHZzIG5vIEFDVCIgLSBhZ2UsIGdlbmRlciwgRUNPRyBhbmQgcGF0aG9sb2dpY2FsIHN0YWdlIC0gQUNUIGFzIHJlZmVyZW5jZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09IlBPU0lUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJEdlbmRlciA8LSBmYWN0b3IoY2lyY19kYXRhJEdlbmRlciwgbGV2ZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkKY2lyY19kYXRhJEFnZS5Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJEFnZS5Hcm91cCwgbGV2ZWxzID0gYygiMSIsICIyIiksIGxhYmVscyA9IGMoIjw3MCIsICI+NzAiKSkKY2lyY19kYXRhJFByaW1TaXRlIDwtIGZhY3RvcihjaXJjX2RhdGEkUHJpbVNpdGUsIGxldmVscyA9IGMoIlJpZ2h0LXNpZGVkIGNvbG9uIiwgIkxlZnQtc2lkZWQgY29sb24iKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpKQpjaXJjX2RhdGEkUG9zdG9wLkNvbXBsaWNhdGlvbiA8LSBmYWN0b3IoY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24sIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKQpjaXJjX2RhdGEkT3hhbGlwbGF0aW4uSGlzdG9yeSA8LSBmYWN0b3IoY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnksIGxldmVscyA9IGMoIk5vIiwgIlllcyIpKQpjaXJjX2RhdGEkTWV0cy5UeXBlIDwtIGZhY3RvcihjaXJjX2RhdGEkTWV0cy5UeXBlLCBsZXZlbHMgPSBjKCJNZXRhY2hyb25vdXMiLCAiU3luY2hyb25vdXMiKSkKY2lyY19kYXRhJE1TSSA8LSBmYWN0b3IoY2lyY19kYXRhJE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIiksIGxhYmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpKQpjaXJjX2RhdGEkQlJBRi5WNjAwRSA8LSBmYWN0b3IoY2lyY19kYXRhJEJSQUYuVjYwMEUsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiVjYwMEUiKSkKY2lyY19kYXRhJFJBUyA8LSBmYWN0b3IoY2lyY19kYXRhJFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIldpbGQtVHlwZSIsICJNdXRhbnQiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gQUNUICsgR2VuZGVyICsgQWdlLkdyb3VwICsgTnVtTGl2ZXJNZXRzR3JvdXAgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIFJBUyArIE1ldHMuVHlwZSArIE94YWxpcGxhdGluLkhpc3RvcnksIGRhdGE9Y2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojREZTIGJ5IEFDVCB0cmVhdG1lbnQgaW4gTVJEIG5lZ2F0aXZlIC0gU3luY2hyb25vdXMgbWV0YXN0YXRpYyBzaXRlCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE1ldHMuVHlwZT09IlN5bmNocm9ub3VzIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5BQ1QsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KEFDVCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoInJlZCIsImJsdWUiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBOZWdhdGl2ZSBBQ1QgdnMgT2JzZXJ2YXRpb24gfCBTeW5jaHJvbm91cyBNZXQgU2l0ZSIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoIk9ic2VydmF0aW9uIiwgIkFDVCIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0KSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzPWMoIlRSVUUiLCJGQUxTRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gQUNULCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAyNApkZnNfdGltZXMgPC0gYygyNCkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiRkFMU0UiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiRkFMU0UiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiRkFMU0UiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQoKcF92YWx1ZXNfYWRqdXN0ZWQgPC0gcC5hZGp1c3QocF92YWx1ZXMsIG1ldGhvZCA9ICJib25mZXJyb25pIikKbmFtZXMocF92YWx1ZXNfYWRqdXN0ZWQpIDwtIHBhc3RlMCgiQ29ycmVjdGVkIHAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzX2FkanVzdGVkKQoKI0FkanVzdGVkIEhSICJBQ1QgdnMgbm8gQUNUIiAtIGFnZSwgZ2VuZGVyLCBFQ09HIGFuZCBwYXRob2xvZ2ljYWwgc3RhZ2UgLSBBQ1QgYXMgcmVmZXJlbmNlCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEPT0iTkVHQVRJVkUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTWV0cy5UeXBlPT0iU3luY2hyb25vdXMiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIj43MCIpKQpjaXJjX2RhdGEkUHJpbVNpdGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKQpjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cCwgbGV2ZWxzID0gYygiMSIsICLiiaUyIikpCmNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJFNpemVMaXZlck1ldHNtbUdyb3VwLCBsZXZlbHMgPSBjKCI8NTAiLCAi4omlNTAiKSkKY2lyY19kYXRhJEVDT0cgPC0gZmFjdG9yKGNpcmNfZGF0YSRFQ09HLCBsZXZlbHMgPSBjKCIwIiwgIjEiKSkKY2lyY19kYXRhJHBUIDwtIGZhY3RvcihjaXJjX2RhdGEkcFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpCmNpcmNfZGF0YSRwTiA8LSBmYWN0b3IoY2lyY19kYXRhJHBOLCBsZXZlbHMgPSBjKCJOMCIsICJOMS1OMiIpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIikpCmNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uIDwtIGZhY3RvcihjaXJjX2RhdGEkUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5IDwtIGZhY3RvcihjaXJjX2RhdGEkT3hhbGlwbGF0aW4uSGlzdG9yeSwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpjaXJjX2RhdGEkTVNJIDwtIGZhY3RvcihjaXJjX2RhdGEkTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSwgbGFiZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpCmNpcmNfZGF0YSRCUkFGLlY2MDBFIDwtIGZhY3RvcihjaXJjX2RhdGEkQlJBRi5WNjAwRSwgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIldpbGQtVHlwZSIsICJWNjAwRSIpKQpjaXJjX2RhdGEkUkFTIDwtIGZhY3RvcihjaXJjX2RhdGEkUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIk11dGFudCIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QgKyBHZW5kZXIgKyBBZ2UuR3JvdXAgKyBOdW1MaXZlck1ldHNHcm91cCArIFNpemVMaXZlck1ldHNtbUdyb3VwICsgUkFTICsgT3hhbGlwbGF0aW4uSGlzdG9yeSwgZGF0YT1jaXJjX2RhdGEpIApzdW1tYXJ5KGNveF9maXQpCmBgYAoKCiNERlMgYnkgQUNUIHRyZWF0bWVudCBpbiBNUkQgbmVnYXRpdmUgLSBNZXRhY2hyb25vdXMgbWV0YXN0YXRpYyBzaXRlCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE1ldHMuVHlwZT09Ik1ldGFjaHJvbm91cyIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+QUNULCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShBQ1QpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gQUNULCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJyZWQiLCJibHVlIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgTmVnYXRpdmUgQUNUIHZzIE9ic2VydmF0aW9uIHwgTWV0YWNocm9ub3VzIE1ldCBTaXRlIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiT2JzZXJ2YXRpb24iLCAiQUNUIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMjQpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiVFJVRSIsIkZBTFNFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDI0CmRmc190aW1lcyA8LSBjKDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgpwX3ZhbHVlc19hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX3ZhbHVlc19hZGp1c3RlZCkgPC0gcGFzdGUwKCJDb3JyZWN0ZWQgcC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXNfYWRqdXN0ZWQpCgojQWRqdXN0ZWQgSFIgIkFDVCB2cyBubyBBQ1QiIC0gYWdlLCBnZW5kZXIsIEVDT0cgYW5kIHBhdGhvbG9naWNhbCBzdGFnZSAtIEFDVCBhcyByZWZlcmVuY2UKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRNZXRzLlR5cGU9PSJNZXRhY2hyb25vdXMiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIj43MCIpKQpjaXJjX2RhdGEkUHJpbVNpdGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKQpjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cCwgbGV2ZWxzID0gYygiMSIsICLiiaUyIikpCmNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJFNpemVMaXZlck1ldHNtbUdyb3VwLCBsZXZlbHMgPSBjKCI8NTAiLCAi4omlNTAiKSkKY2lyY19kYXRhJEVDT0cgPC0gZmFjdG9yKGNpcmNfZGF0YSRFQ09HLCBsZXZlbHMgPSBjKCIwIiwgIjEiKSkKY2lyY19kYXRhJHBUIDwtIGZhY3RvcihjaXJjX2RhdGEkcFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpCmNpcmNfZGF0YSRwTiA8LSBmYWN0b3IoY2lyY19kYXRhJHBOLCBsZXZlbHMgPSBjKCJOMCIsICJOMS1OMiIpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIikpCmNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uIDwtIGZhY3RvcihjaXJjX2RhdGEkUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5IDwtIGZhY3RvcihjaXJjX2RhdGEkT3hhbGlwbGF0aW4uSGlzdG9yeSwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpjaXJjX2RhdGEkTVNJIDwtIGZhY3RvcihjaXJjX2RhdGEkTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSwgbGFiZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpCmNpcmNfZGF0YSRCUkFGLlY2MDBFIDwtIGZhY3RvcihjaXJjX2RhdGEkQlJBRi5WNjAwRSwgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIldpbGQtVHlwZSIsICJWNjAwRSIpKQpjaXJjX2RhdGEkUkFTIDwtIGZhY3RvcihjaXJjX2RhdGEkUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIk11dGFudCIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QgKyBHZW5kZXIgKyBBZ2UuR3JvdXAgKyBOdW1MaXZlck1ldHNHcm91cCArIFNpemVMaXZlck1ldHNtbUdyb3VwICsgUkFTICsgT3hhbGlwbGF0aW4uSGlzdG9yeSwgZGF0YT1jaXJjX2RhdGEpIApzdW1tYXJ5KGNveF9maXQpCmBgYAoKCiNERlMgYnkgQUNUIHRyZWF0bWVudCBpbiBNUkQgbmVnYXRpdmUgLSAxIExpdmVyIE1ldApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cD09IjEiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfkFDVCwgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoQUNUKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IEFDVCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygicmVkIiwiYmx1ZSIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIE5lZ2F0aXZlIEFDVCB2cyBPYnNlcnZhdGlvbiB8IDEgTGl2ZXIgTWV0IiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiT2JzZXJ2YXRpb24iLCAiQUNUIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMjQpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiVFJVRSIsIkZBTFNFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDI0CmRmc190aW1lcyA8LSBjKDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkQUNUID09ICJGQUxTRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgpwX3ZhbHVlc19hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX3ZhbHVlc19hZGp1c3RlZCkgPC0gcGFzdGUwKCJDb3JyZWN0ZWQgcC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXNfYWRqdXN0ZWQpCgojQWRqdXN0ZWQgSFIgIkFDVCB2cyBubyBBQ1QiIC0gYWdlLCBnZW5kZXIsIEVDT0cgYW5kIHBhdGhvbG9naWNhbCBzdGFnZSAtIEFDVCBhcyByZWZlcmVuY2UKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cD09IjEiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkQWdlLkdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkQWdlLkdyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIjIiKSwgbGFiZWxzID0gYygiPDcwIiwgIj43MCIpKQpjaXJjX2RhdGEkUHJpbVNpdGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRQcmltU2l0ZSwgbGV2ZWxzID0gYygiUmlnaHQtc2lkZWQgY29sb24iLCAiTGVmdC1zaWRlZCBjb2xvbiIpKQpjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cCwgbGV2ZWxzID0gYygiMSIsICLiiaUyIikpCmNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJFNpemVMaXZlck1ldHNtbUdyb3VwLCBsZXZlbHMgPSBjKCI8NTAiLCAi4omlNTAiKSkKY2lyY19kYXRhJEVDT0cgPC0gZmFjdG9yKGNpcmNfZGF0YSRFQ09HLCBsZXZlbHMgPSBjKCIwIiwgIjEiKSkKY2lyY19kYXRhJHBUIDwtIGZhY3RvcihjaXJjX2RhdGEkcFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpCmNpcmNfZGF0YSRwTiA8LSBmYWN0b3IoY2lyY19kYXRhJHBOLCBsZXZlbHMgPSBjKCJOMCIsICJOMS1OMiIpKQpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIikpCmNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uIDwtIGZhY3RvcihjaXJjX2RhdGEkUG9zdG9wLkNvbXBsaWNhdGlvbiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5IDwtIGZhY3RvcihjaXJjX2RhdGEkT3hhbGlwbGF0aW4uSGlzdG9yeSwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpCmNpcmNfZGF0YSRNZXRzLlR5cGUgPC0gZmFjdG9yKGNpcmNfZGF0YSRNZXRzLlR5cGUsIGxldmVscyA9IGMoIk1ldGFjaHJvbm91cyIsICJTeW5jaHJvbm91cyIpKQpjaXJjX2RhdGEkTVNJIDwtIGZhY3RvcihjaXJjX2RhdGEkTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSwgbGFiZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpCmNpcmNfZGF0YSRCUkFGLlY2MDBFIDwtIGZhY3RvcihjaXJjX2RhdGEkQlJBRi5WNjAwRSwgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIldpbGQtVHlwZSIsICJWNjAwRSIpKQpjaXJjX2RhdGEkUkFTIDwtIGZhY3RvcihjaXJjX2RhdGEkUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIk11dGFudCIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBQ1QgKyBHZW5kZXIgKyBBZ2UuR3JvdXAgKyBNZXRzLlR5cGUgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIFJBUyArIE94YWxpcGxhdGluLkhpc3RvcnksIGRhdGE9Y2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojREZTIGJ5IEFDVCB0cmVhdG1lbnQgaW4gTVJEIG5lZ2F0aXZlIC0gMuKJpSBMaXZlciBNZXRzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwPT0i4omlMiIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+QUNULCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShBQ1QpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gQUNULCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJyZWQiLCJibHVlIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgTmVnYXRpdmUgQUNUIHZzIE9ic2VydmF0aW9uIHwg4omlMiBMaXZlciBNZXQiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJPYnNlcnZhdGlvbiIsICJBQ1QiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCkpCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscz1jKCJUUlVFIiwiRkFMU0UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMjQKZGZzX3RpbWVzIDwtIGMoMjQpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCnBfdmFsdWVzX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCm5hbWVzKHBfdmFsdWVzX2FkanVzdGVkKSA8LSBwYXN0ZTAoIkNvcnJlY3RlZCBwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlc19hZGp1c3RlZCkKCiNBZGp1c3RlZCBIUiAiQUNUIHZzIG5vIEFDVCIgLSBhZ2UsIGdlbmRlciwgRUNPRyBhbmQgcGF0aG9sb2dpY2FsIHN0YWdlIC0gQUNUIGFzIHJlZmVyZW5jZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwPT0i4omlMiIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJSaWdodC1zaWRlZCBjb2xvbiIsICJMZWZ0LXNpZGVkIGNvbG9uIikpCmNpcmNfZGF0YSROdW1MaXZlck1ldHNHcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwLCBsZXZlbHMgPSBjKCIxIiwgIuKJpTIiKSkKY2lyY19kYXRhJFNpemVMaXZlck1ldHNtbUdyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAsIGxldmVscyA9IGMoIjw1MCIsICLiiaU1MCIpKQpjaXJjX2RhdGEkRUNPRyA8LSBmYWN0b3IoY2lyY19kYXRhJEVDT0csIGxldmVscyA9IGMoIjAiLCAiMSIpKQpjaXJjX2RhdGEkcFQgPC0gZmFjdG9yKGNpcmNfZGF0YSRwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSkKY2lyY19kYXRhJHBOIDwtIGZhY3RvcihjaXJjX2RhdGEkcE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscyA9IGMoIkZBTFNFIiwgIlRSVUUiKSkKY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uLCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnkgPC0gZmFjdG9yKGNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5LCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNpcmNfZGF0YSRNU0kgPC0gZmFjdG9yKGNpcmNfZGF0YSRNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpLCBsYWJlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSkKY2lyY19kYXRhJEJSQUYuVjYwMEUgPC0gZmFjdG9yKGNpcmNfZGF0YSRCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIlY2MDBFIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCArIEdlbmRlciArIEFnZS5Hcm91cCArIE1ldHMuVHlwZSArIFJBUyArIE94YWxpcGxhdGluLkhpc3RvcnksIGRhdGE9Y2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojREZTIGJ5IGN0RE5BIENsZWFyYW5jZSBBQ1QtdHJlYXRlZCBhdCAzIG1vbnRocwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRBQ1Q9PVRSVUUsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuM21vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuM21vbnRocyA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuM21vLm1vbnRocz49MCxdCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy4zbW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5EeW5hbWljcykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuM21vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIENsZWFyYW5jZSBmcm9tIE1SRCB0byAzIG1vbnRocyBBQ1QtdHJlYXRlZCIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoIkNsZWFyYW5jZSIsICJObyBDbGVhcmFuY2UiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYyg2LCAxMiwgMjQpKQpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgbGV2ZWxzPWMoIjEiLCIyIiksIGxhYmVscyA9IGMoIkNsZWFyYW5jZSIsICJObyBDbGVhcmFuY2UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQpgYGAKCgojTGV2ZWxzIG9mIE1SRCBNVE0vbUwgaW4gQ2xlYXJhbmNlIGF0IDMgbW9udGhzIGxvZzEwIHRyYW5zZm9ybWF0aW9uCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJEFDVD09VFJVRSxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkNsZWFyYW5jZSA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5DbGVhcmFuY2UgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjNtb250aHMgPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLjNtb250aHMgPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLjNtby5tb250aHM+PTAsXQpjaXJjX2RhdGEgPC0gc3Vic2V0KGNpcmNfZGF0YSwgIWlzLm5hKGN0RE5BLkNsZWFyYW5jZSkpCgojIFRyYW5zZm9ybSBwX01SRF9NVE0gd2l0aCBsb2cxMApjaXJjX2RhdGEkcF9NUkRfTVRNIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNpcmNfZGF0YSRwX01SRF9NVE0pKQpjaXJjX2RhdGEkY3RETkEuQ2xlYXJhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuQ2xlYXJhbmNlLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQptZWRpYW5fcF9NUkRfTVRNIDwtIGFnZ3JlZ2F0ZShwX01SRF9NVE0gfiBjdEROQS5DbGVhcmFuY2UsIGRhdGEgPSBjaXJjX2RhdGEsIEZVTiA9IG1lZGlhbikKcHJpbnQobWVkaWFuX3BfTVJEX01UTSkKCiMgQ3JlYXRlIHZpb2xpbiBwbG90IHdpdGggbG9nMTAgc2NhbGUgb24geS1heGlzCmdncGxvdChjaXJjX2RhdGEsIGFlcyh4PWN0RE5BLkNsZWFyYW5jZSwgeT1wX01SRF9NVE0sIGZpbGw9Y3RETkEuQ2xlYXJhbmNlKSkgKwogIGdlb21fdmlvbGluKHRyaW09RkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiQ2xlYXJhbmNlIj0ibGlnaHRibHVlIiwgIk5vIENsZWFyYW5jZSI9InNhbG1vbiIpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMSwgZmlsbD0id2hpdGUiLCBjb2xvdXI9ImJsYWNrIiwgYWxwaGE9MC41KSArCiAgc2NhbGVfeV9sb2cxMChicmVha3M9YygwLjAwMSwgMC4wMSwgMC4xLCAxLCAxMCwgMTAwLCAxMDAwLCAxMDAwMCkpICsKICBsYWJzKHRpdGxlPSJNUkQgTVRNL21MIHwgQ2xlYXJhbmNlIGF0IDMgbW9udGhzIiwgeD0iQ2xlYXJhbmNlIGF0IDMgbW9udGhzIiwgeT0iTVJEIE1UTS9tTCIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCm0zXzF2MiA8LSB3aWxjb3gudGVzdChwX01SRF9NVE0gfiBjdEROQS5DbGVhcmFuY2UsCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5DbGVhcmFuY2UgJWluJSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIiksIF0sCiAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpCnByaW50KG0zXzF2MikKYGBgCgojREZTIGJ5IGN0RE5BIENsZWFyYW5jZSBBQ1QtdHJlYXRlZCBhdCA2IG1vbnRocwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRBQ1Q9PVRSVUUsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuNm1vLm1vbnRocz49MCxdCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy42bW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5EeW5hbWljcykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIENsZWFyYW5jZSBmcm9tIE1SRCB0byA2IG1vbnRocyBBQ1QtdHJlYXRlZCIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoIkNsZWFyYW5jZSIsICJObyBDbGVhcmFuY2UiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYyg2LCAyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCmBgYAoKCiNMZXZlbHMgb2YgTVJEIE1UTS9tTCBpbiBDbGVhcmFuY2UgYXQgNiBtb250aHMgbG9nMTAgdHJhbnNmb3JtYXRpb24KYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQUNUPT1UUlVFLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuQ2xlYXJhbmNlIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkNsZWFyYW5jZSA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuNm1vLm1vbnRocz49MCxdCmNpcmNfZGF0YSA8LSBzdWJzZXQoY2lyY19kYXRhLCAhaXMubmEoY3RETkEuQ2xlYXJhbmNlKSkKCiMgVHJhbnNmb3JtIHBfTVJEX01UTSB3aXRoIGxvZzEwCmNpcmNfZGF0YSRwX01SRF9NVE0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY2lyY19kYXRhJHBfTVJEX01UTSkpCmNpcmNfZGF0YSRjdEROQS5DbGVhcmFuY2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5DbGVhcmFuY2UsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCm1lZGlhbl9wX01SRF9NVE0gPC0gYWdncmVnYXRlKHBfTVJEX01UTSB+IGN0RE5BLkNsZWFyYW5jZSwgZGF0YSA9IGNpcmNfZGF0YSwgRlVOID0gbWVkaWFuKQpwcmludChtZWRpYW5fcF9NUkRfTVRNKQoKIyBDcmVhdGUgdmlvbGluIHBsb3Qgd2l0aCBsb2cxMCBzY2FsZSBvbiB5LWF4aXMKZ2dwbG90KGNpcmNfZGF0YSwgYWVzKHg9Y3RETkEuQ2xlYXJhbmNlLCB5PXBfTVJEX01UTSwgZmlsbD1jdEROQS5DbGVhcmFuY2UpKSArCiAgZ2VvbV92aW9saW4odHJpbT1GQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJDbGVhcmFuY2UiPSJsaWdodGJsdWUiLCAiTm8gQ2xlYXJhbmNlIj0ic2FsbW9uIikpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9MC4xLCBmaWxsPSJ3aGl0ZSIsIGNvbG91cj0iYmxhY2siLCBhbHBoYT0wLjUpICsKICBzY2FsZV95X2xvZzEwKGJyZWFrcz1jKDAuMDAxLCAwLjAxLCAwLjEsIDEsIDEwLCAxMDAsIDEwMDAsIDEwMDAwKSkgKwogIGxhYnModGl0bGU9Ik1SRCBNVE0vbUwgfCBDbGVhcmFuY2UgYXQgNiBtb250aHMiLCB4PSJDbGVhcmFuY2UgYXQgNiBtb250aHMiLCB5PSJNUkQgTVRNL21MIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKbTNfMXYyIDwtIHdpbGNveC50ZXN0KHBfTVJEX01UTSB+IGN0RE5BLkNsZWFyYW5jZSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkNsZWFyYW5jZSAlaW4lIGMoIkNsZWFyYW5jZSIsICJObyBDbGVhcmFuY2UiKSwgXSwKICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkKcHJpbnQobTNfMXYyKQpgYGAKCiNERlMgYnkgY3RETkEgYXQgdGhlIFN1cnZlaWxsYW5jZSBXaW5kb3cgLSBMYW5kbWFyayAxMCB3ZWVrcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSE9IiIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yLjUKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLlN1cnZlaWxsYW5jZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIFN1cnZlaWxsYW5jZSB3aW5kb3ciLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0LCAzMCwgMzYpKQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAyNCwgMzAsIGFuZCAzNiBtb250aHMKZGZzX3RpbWVzIDwtIGMoMjQsIDMwLCAzNikKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQoKcF92YWx1ZXNfYWRqdXN0ZWQgPC0gcC5hZGp1c3QocF92YWx1ZXMsIG1ldGhvZCA9ICJib25mZXJyb25pIikKbmFtZXMocF92YWx1ZXNfYWRqdXN0ZWQpIDwtIHBhc3RlMCgiQ29ycmVjdGVkIHAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzX2FkanVzdGVkKQpgYGAKCgoKCiNPUyBieSBjdEROQSBhdCB0aGUgU3VydmVpbGxhbmNlIFdpbmRvdyAtIExhbmRtYXJrIDEwIHdlZWtzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIT0iIixdCmNpcmNfZGF0YSRPUy5tb250aHM9Y2lyY19kYXRhJE9TLm1vbnRocy0yLjUKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkT1MubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJE9TLkV2ZW50KX5jdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLlN1cnZlaWxsYW5jZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oT1MuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9Ik9TIC0gY3RETkEgU3VydmVpbGxhbmNlIHdpbmRvdyIsIHlsYWI9ICJPdmVyYWxsIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0LCAzMCwgMzYpKQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIE9TIHBlcmNlbnRhZ2VzIGF0IDI0LCAzMCwgYW5kIDM2IG1vbnRocwpvc190aW1lcyA8LSBjKDI0LCAzMCwgMzYpCnBfdmFsdWVzIDwtIHNhcHBseShvc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJE9TLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJE9TLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkT1MubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkT1MuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJE9TLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkT1MubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJE9TLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkT1MubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIG9zX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQoKcF92YWx1ZXNfYWRqdXN0ZWQgPC0gcC5hZGp1c3QocF92YWx1ZXMsIG1ldGhvZCA9ICJib25mZXJyb25pIikKbmFtZXMocF92YWx1ZXNfYWRqdXN0ZWQpIDwtIHBhc3RlMCgiQ29ycmVjdGVkIHAtdmFsdWUgYXQgIiwgb3NfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXNfYWRqdXN0ZWQpCmBgYAoKCgoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93IGZvciBERlMgLSBMYW5kbWFyayAxMCB3ZWVrcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSE9IiIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yLjUKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENFQS5CYXNlbGluZSA8LSBmYWN0b3IoY2lyY19kYXRhJENFQS5CYXNlbGluZSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTm9ybWFsIiwgIkVsZXZhdGVkIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJSaWdodC1zaWRlZCBjb2xvbiIsICJMZWZ0LXNpZGVkIGNvbG9uIiksIGxhYmVscyA9IGMoIlJpZ2h0LXNpZGVkIiwgIkxlZnQtc2lkZWQiKSkKY2lyY19kYXRhJE51bUxpdmVyTWV0c0dyb3VwIDwtIGZhY3RvcihjaXJjX2RhdGEkTnVtTGl2ZXJNZXRzR3JvdXAsIGxldmVscyA9IGMoIjEiLCAi4omlMiIpKQpjaXJjX2RhdGEkU2l6ZUxpdmVyTWV0c21tR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRTaXplTGl2ZXJNZXRzbW1Hcm91cCwgbGV2ZWxzID0gYygiPDUwIiwgIuKJpTUwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJEFDVCA8LSBmYWN0b3IoY2lyY19kYXRhJEFDVCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJPYnNlcnZhdGlvbiIsICJDaGVtb3RoZXJhcHkiKSkKY2lyY19kYXRhJFBvc3RvcC5Db21wbGljYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRQb3N0b3AuQ29tcGxpY2F0aW9uLCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE94YWxpcGxhdGluLkhpc3RvcnkgPC0gZmFjdG9yKGNpcmNfZGF0YSRPeGFsaXBsYXRpbi5IaXN0b3J5LCBsZXZlbHMgPSBjKCJObyIsICJZZXMiKSkKY2lyY19kYXRhJE1ldHMuVHlwZSA8LSBmYWN0b3IoY2lyY19kYXRhJE1ldHMuVHlwZSwgbGV2ZWxzID0gYygiTWV0YWNocm9ub3VzIiwgIlN5bmNocm9ub3VzIikpCmNpcmNfZGF0YSRNU0kgPC0gZmFjdG9yKGNpcmNfZGF0YSRNU0ksIGxldmVscyA9IGMoIk1TUyIsICJNU0ktSGlnaCIpLCBsYWJlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSkKY2lyY19kYXRhJEJSQUYuVjYwMEUgPC0gZmFjdG9yKGNpcmNfZGF0YSRCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiV2lsZC1UeXBlIiwgIlY2MDBFIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLlN1cnZlaWxsYW5jZSArIENFQS5CYXNlbGluZSArIEFnZS5Hcm91cCArIFByaW1TaXRlICsgTnVtTGl2ZXJNZXRzR3JvdXAgKyBTaXplTGl2ZXJNZXRzbW1Hcm91cCArIHBUICsgcE4gKyBSQVMgKyBNZXRzLlR5cGUgKyBQb3N0b3AuQ29tcGxpY2F0aW9uICsgT3hhbGlwbGF0aW4uSGlzdG9yeSwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBERlMiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI09TIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93IC0gcHRzIHdpdGggUmFkaW9sb2dpY2FsIFJlY3VycmVuY2UKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQ9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRPUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKE9TLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iT1MgLSBSYWRpb2xvZ2ljYWwgUmVjdXJyZW5jZSB8IGN0RE5BIE1SRCB3aW5kb3ciLCB5bGFiPSAiT3ZlcmFsbCBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCwgMzYpKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIE9TIHBlcmNlbnRhZ2VzIGF0IDI0IGFuZCAzNiBtb250aHMKb3NfdGltZXMgPC0gYygyNCwgMzYpCnBfdmFsdWVzIDwtIHNhcHBseShvc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJE9TLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRPUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJE9TLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRPUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkT1MuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRPUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJE9TLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkT1MuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBvc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCnBfdmFsdWVzX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCm5hbWVzKHBfdmFsdWVzX2FkanVzdGVkKSA8LSBwYXN0ZTAoIkNvcnJlY3RlZCBwLXZhbHVlIGF0ICIsIG9zX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzX2FkanVzdGVkKQpgYGAKCiNQZXJjZW50YWdlIG9mIGN0RE5BIE1SRCBXaW5kb3cgcG9zaXRpdml0eSBpbiBwdHMgd2l0aCBsaXZlciBtZXRhc3Rhc2lzCmBgYHtyfQoKcm0obGlzdCA9IGxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgZmlsdGVyKExpdmVyTWV0cyA9PSAiVFJVRSIgJiBSRlMuRXZlbnQgPT0gIlRSVUUiICYgY3RETkEuTVJEICE9ICIiKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpLCBsYWJlbHMgPSBjKCJOZWdhdGl2ZSIsICJQb3NpdGl2ZSIpKQpwb3NpdGl2ZV9yYXRlIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQb3NpdGl2ZSIgJiBncmVwbCgibGl2ZXIiLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSkgLyBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUG9zaXRpdmUiKSAqIDEwMApwb3NpdGl2ZV9jaSA8LSBiaW5jb25mKHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQb3NpdGl2ZSIgJiBncmVwbCgibGl2ZXIiLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBvc2l0aXZlIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KVtjKDIsIDMpXSAqIDEwMApuZWdhdGl2ZV9yYXRlIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJOZWdhdGl2ZSIgJiBncmVwbCgibGl2ZXIiLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSkgLyBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTmVnYXRpdmUiKSAqIDEwMApuZWdhdGl2ZV9jaSA8LSBiaW5jb25mKHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJOZWdhdGl2ZSIgJiBncmVwbCgibGl2ZXIiLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5lZ2F0aXZlIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KVtjKDIsIDMpXSAqIDEwMApkYXRhIDwtIGRhdGEuZnJhbWUoCiAgY3RETkEuTVJEID0gYygiUG9zaXRpdmUiLCAiTmVnYXRpdmUiKSwKICBwZXJjZW50YWdlID0gYyhwb3NpdGl2ZV9yYXRlLCBuZWdhdGl2ZV9yYXRlKSwKICBsb3dlcl9jaSA9IGMocG9zaXRpdmVfY2lbMV0sIG5lZ2F0aXZlX2NpWzFdKSwKICB1cHBlcl9jaSA9IGMocG9zaXRpdmVfY2lbMl0sIG5lZ2F0aXZlX2NpWzJdKQopCmNyb3NzX3RhYnMgPC0gbGlzdCgKICB0YWJsZShjaXJjX2RhdGEkY3RETkEuTVJELCBncmVwbCgibGl2ZXIiLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSksCiAgdGFibGUoY2lyY19kYXRhJGN0RE5BLk1SRCwgZ3JlcGwoImx1bmciLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSkKKQpjaGlfdGVzdHMgPC0gbGFwcGx5KGNyb3NzX3RhYnMsIGNoaXNxLnRlc3QpCnBfdmFsdWVzIDwtIHNhcHBseShjaGlfdGVzdHMsIGZ1bmN0aW9uKHRlc3QpIHRlc3QkcC52YWx1ZSkKbnVtX3Rlc3RzIDwtIGxlbmd0aChwX3ZhbHVlcykgICMgTnVtYmVyIG9mIHRlc3RzIHRvIGJlIGFkanVzdGVkIGZvcgpwX3ZhbHVlc19hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiLCBuID0gbnVtX3Rlc3RzKQpwcmludChkYXRhKQpwcmludChjcm9zc190YWJzKQpwcmludChjaGlfdGVzdHMpCnByaW50KHBhc3RlKCJPcmlnaW5hbCBwLXZhbHVlczoiLCBmb3JtYXQucHZhbChwX3ZhbHVlcywgZGlnaXRzID0gNCkpKQpwcmludChwYXN0ZSgiQWRqdXN0ZWQgcC12YWx1ZXMgKEJvbmZlcnJvbmkpOiIsIGZvcm1hdC5wdmFsKHBfdmFsdWVzX2FkanVzdGVkLCBkaWdpdHMgPSA0KSkpCmJhcnBsb3QgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gY3RETkEuTVJELCB5ID0gcGVyY2VudGFnZSwgZmlsbCA9IGN0RE5BLk1SRCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBsb3dlcl9jaSwgeW1heCA9IHVwcGVyX2NpKSwgd2lkdGggPSAwLjIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSIpKSwgdmp1c3QgPSAtMC41KSArCiAgbGFicygKICAgIHggPSAiY3RETkEgc3RhdHVzIGF0IHRoZSBNUkQgc3RhdHVzIiwKICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBwYXRpZW50cyB3aXRoIHJlY3VycmVuY2UgaW4gdGhlIGxpdmVyIiwKICAgIGNhcHRpb24gPSBwYXN0ZSgiQ2hpLXNxdWFyZWQgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChwX3ZhbHVlc1sxXSwgZGlnaXRzID0gNCksIAogICAgICAgICAgICAgICAgICAgICJcbkFkanVzdGVkIHAtdmFsdWUgKEJvbmZlcnJvbmkpOiAiLCBmb3JtYXQucHZhbChwX3ZhbHVlc19hZGp1c3RlZFsxXSwgZGlnaXRzID0gNCkpCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgMTAwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5lZ2F0aXZlIiA9ICJibHVlIiwgIlBvc2l0aXZlIiA9ICJyZWQiKSkgKwogIHRoZW1lX21pbmltYWwoKQpwcmludChiYXJwbG90KQpgYGAKCgojUGVyY2VudGFnZSBvZiBjdEROQSBNUkQgV2luZG93IHBvc2l0aXZpdHkgaW4gcHRzIHdpdGggbHVuZyBtZXRhc3Rhc2lzCmBgYHtyfQpybShsaXN0ID0gbHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBmaWx0ZXIoTGl2ZXJNZXRzID09ICJUUlVFIiAmIFJGUy5FdmVudCA9PSAiVFJVRSIgJiBjdEROQS5NUkQgIT0gIiIpCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCnBvc2l0aXZlX3JhdGUgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBvc2l0aXZlIiAmIGdyZXBsKCJsdW5nIiwgY2lyY19kYXRhJFJlbFNpdGUsIGlnbm9yZS5jYXNlID0gVFJVRSkpIC8gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBvc2l0aXZlIikgKiAxMDAKcG9zaXRpdmVfY2kgPC0gYmluY29uZihzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUG9zaXRpdmUiICYgZ3JlcGwoImx1bmciLCBjaXJjX2RhdGEkUmVsU2l0ZSwgaWdub3JlLmNhc2UgPSBUUlVFKSksCiAgICAgICAgICAgICAgICAgICAgICAgc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBvc2l0aXZlIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KVtjKDIsIDMpXSAqIDEwMApuZWdhdGl2ZV9yYXRlIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJOZWdhdGl2ZSIgJiBncmVwbCgibHVuZyIsIGNpcmNfZGF0YSRSZWxTaXRlLCBpZ25vcmUuY2FzZSA9IFRSVUUpKSAvIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJOZWdhdGl2ZSIpICogMTAwCm5lZ2F0aXZlX2NpIDwtIGJpbmNvbmYoc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5lZ2F0aXZlIiAmIGdyZXBsKCJsdW5nIiwgY2lyY19kYXRhJFJlbFNpdGUsIGlnbm9yZS5jYXNlID0gVFJVRSkpLAogICAgICAgICAgICAgICAgICAgICAgIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJOZWdhdGl2ZSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSlbYygyLCAzKV0gKiAxMDAKZGF0YSA8LSBkYXRhLmZyYW1lKAogIGN0RE5BLk1SRCA9IGMoIlBvc2l0aXZlIiwgIk5lZ2F0aXZlIiksCiAgcGVyY2VudGFnZSA9IGMocG9zaXRpdmVfcmF0ZSwgbmVnYXRpdmVfcmF0ZSksCiAgbG93ZXJfY2kgPSBjKHBvc2l0aXZlX2NpWzFdLCBuZWdhdGl2ZV9jaVsxXSksCiAgdXBwZXJfY2kgPSBjKHBvc2l0aXZlX2NpWzJdLCBuZWdhdGl2ZV9jaVsyXSkKKQoKY3Jvc3NfdGFicyA8LSBsaXN0KAogIHRhYmxlKGNpcmNfZGF0YSRjdEROQS5NUkQsIGdyZXBsKCJsdW5nIiwgY2lyY19kYXRhJFJlbFNpdGUsIGlnbm9yZS5jYXNlID0gVFJVRSkpLAogIHRhYmxlKGNpcmNfZGF0YSRjdEROQS5NUkQsIGdyZXBsKCJsaXZlciIsIGNpcmNfZGF0YSRSZWxTaXRlLCBpZ25vcmUuY2FzZSA9IFRSVUUpKQopCmNoaV90ZXN0cyA8LSBsYXBwbHkoY3Jvc3NfdGFicywgY2hpc3EudGVzdCkKcF92YWx1ZXMgPC0gc2FwcGx5KGNoaV90ZXN0cywgZnVuY3Rpb24odGVzdCkgdGVzdCRwLnZhbHVlKQpudW1fdGVzdHMgPC0gbGVuZ3RoKHBfdmFsdWVzKSAgIyBOdW1iZXIgb2YgdGVzdHMgdG8gYmUgYWRqdXN0ZWQgZm9yCnBfdmFsdWVzX2FkanVzdGVkIDwtIHAuYWRqdXN0KHBfdmFsdWVzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIsIG4gPSBudW1fdGVzdHMpCnByaW50KGRhdGEpCnByaW50KGNyb3NzX3RhYnMpCnByaW50KGNoaV90ZXN0cykKcHJpbnQocGFzdGUoIk9yaWdpbmFsIHAtdmFsdWVzOiIsIGZvcm1hdC5wdmFsKHBfdmFsdWVzLCBkaWdpdHMgPSA0KSkpCnByaW50KHBhc3RlKCJBZGp1c3RlZCBwLXZhbHVlcyAoQm9uZmVycm9uaSk6IiwgZm9ybWF0LnB2YWwocF92YWx1ZXNfYWRqdXN0ZWQsIGRpZ2l0cyA9IDQpKSkKYmFycGxvdCA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBjdEROQS5NUkQsIHkgPSBwZXJjZW50YWdlLCBmaWxsID0gY3RETkEuTVJEKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGxvd2VyX2NpLCB5bWF4ID0gdXBwZXJfY2kpLCB3aWR0aCA9IDAuMikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQocGVyY2VudGFnZSwgMSksICIlIikpLCB2anVzdCA9IC0wLjUpICsKICBsYWJzKAogICAgeCA9ICJjdEROQSBzdGF0dXMgYXQgdGhlIE1SRCBzdGF0dXMiLAogICAgeSA9ICJQcm9wb3J0aW9uIG9mIHBhdGllbnRzIHdpdGggcmVjdXJyZW5jZSBpbiB0aGUgbHVuZyIsCiAgICBjYXB0aW9uID0gcGFzdGUoIkNoaS1zcXVhcmVkIHRlc3QgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwocF92YWx1ZXNbMV0sIGRpZ2l0cyA9IDQpLCAKICAgICAgICAgICAgICAgICAgICAiXG5BZGp1c3RlZCBwLXZhbHVlIChCb25mZXJyb25pKTogIiwgZm9ybWF0LnB2YWwocF92YWx1ZXNfYWRqdXN0ZWRbMV0sIGRpZ2l0cyA9IDQpKQogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIDEwMCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJOZWdhdGl2ZSIgPSAiYmx1ZSIsICJQb3NpdGl2ZSIgPSAicmVkIikpICsKICB0aGVtZV9taW5pbWFsKCkKcHJpbnQoYmFycGxvdCkKYGBgCgoKI0JhcnBsb3Qgd2l0aCBSZWN1cnJlbmNlIFNpdGVzIChMaXZlciB2cyBPdGhlcnMpIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUkZTLkV2ZW50PT0iVFJVRSIsXQoKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJExpdmVyIDwtIGZhY3RvcihjaXJjX2RhdGEkTGl2ZXIsIGxldmVscyA9IGMoIkZBTFNFIiwgIlRSVUUiKSwgbGFiZWxzID0gYygiT3RoZXJzIiwgIkxpdmVyIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRjdEROQS5NUkQsIGNpcmNfZGF0YSRMaXZlcikKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKcF92YWx1ZXMgPC0gYyhjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSwgZmlzaGVyX2V4YWN0X3Rlc3QkcC52YWx1ZSkKcF9hZGp1c3RlZCA8LSBwLmFkanVzdChwX3ZhbHVlcywgbWV0aG9kID0gImJvbmZlcnJvbmkiKQpuYW1lcyhwX2FkanVzdGVkKSA8LSBjKCJDaGktU3F1YXJlIFRlc3QiLCAiRmlzaGVyJ3MgRXhhY3QgVGVzdCIpCnByaW50KHBfYWRqdXN0ZWQpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiUGF0aWVudHMgd2l0aCBSYWRpb2xvZ2ljYWwgUmVjdXJyZW5jZSIsIAogICAgICAgeCA9ICJjdEROQSBhdCB0aGUgTVJEIFdpbmRvdyIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiUmVjdXJyZW5jZSBTaXRlIiwKICAgICAgIGNhcHRpb24gPSBwYXN0ZSgiQ2hpLXNxdWFyZWQgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSksICI7IEJvbmZlcnJvbmkgY29ycmVjdGVkIHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKHBfYWRqdXN0ZWRbIkNoaS1TcXVhcmUgVGVzdCJdKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiT3RoZXJzIiA9ICJibHVlIiwgIkxpdmVyIiA9ICJyZWQiKSkgKyAjIGRlZmluZSBjdXN0b20gY29sb3JzCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEuNSwgc2l6ZSA9IDE0KSwgIyBpbmNyZWFzZSB4LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHgtYXhpcyBsYWJlbCBzaXplCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSkgICMgaW5jcmVhc2UgUmVjdXJyZW5jZSBsYWJlbCBzaXplCmBgYAoKI1RhYmxlIHdpdGggcmVjdXJyZW5jZSBzaXRlcyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBMaXZlciBNZXRzIERhdGFfMjAyNDA2MjYgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRMaXZlck1ldHM9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJFJGUy5FdmVudD09IlRSVUUiLF0KCmNpcmNfZGF0YV9zdWJzZXQxIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBSZWMuU2l0ZSkgJT4lCiAgbXV0YXRlKAogICAgUmVjLlNpdGUgPSBmYWN0b3IoUmVjLlNpdGUsIGxldmVscyA9IGMoIkxvY2FsL0xOIiwgIkxpdmVyIiwgIkx1bmciLCAiUGVyaXRvbmV1bSIsICJQZXJpdG9uZXVtICYgT3RoZXJzIiwgIkJyYWluIikpKQoKY2lyY19kYXRhMSA8LSByZWFkLmNzdigiR2FsYXh5IExpdmVyIE1ldHMgRGF0YV8yMDI0MDYyNiBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YTEgPC0gY2lyY19kYXRhMVtjaXJjX2RhdGExJExpdmVyTWV0cz09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUkZTLkV2ZW50PT0iVFJVRSIsXQoKY2lyY19kYXRhX3N1YnNldDIgPC0gY2lyY19kYXRhICU+JQogIHNlbGVjdCgKICAgIFJlYy5TaXRlLAogICAgY3RETkEuTVJEKSAlPiUKICBtdXRhdGUoCiAgICBSZWMuU2l0ZSA9IGZhY3RvcihSZWMuU2l0ZSwgbGV2ZWxzID0gYygiTG9jYWwvTE4iLCAiTGl2ZXIiLCAiTHVuZyIsICJQZXJpdG9uZXVtIiwgIlBlcml0b25ldW0gJiBPdGhlcnMiLCAiQnJhaW4iKSksCiAgICBjdEROQS5NUkQgPSBmYWN0b3IoY3RETkEuTVJELCBsZXZlbHMgPSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKSkKT3ZlcmFsbCA8LSBjaXJjX2RhdGFfc3Vic2V0MSAlPiUKICB0Ymxfc3VtbWFyeSgKICAgIHN0YXRpc3RpYyA9IGxpc3QoCiAgICAgIGFsbF9jb250aW51b3VzKCkgfiAie21lZGlhbn0gKHttaW59IC0ge21heH0pIiwKICAgICAgYWxsX2NhdGVnb3JpY2FsKCkgfiAie259ICh7cH0lKSIpKSAlPiUKICBib2xkX2xhYmVscygpCk92ZXJhbGwKCkJ5Y3RETkFfTVJEIDwtIGNpcmNfZGF0YV9zdWJzZXQyICU+JQogIHRibF9zdW1tYXJ5KAogICAgYnkgPSBjdEROQS5NUkQsICMgU3ViZ3JvdXAgYnkgY3RETkEuTVJECiAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICBhbGxfY29udGludW91cygpIH4gInttZWRpYW59ICh7bWlufSAtIHttYXh9KSIsCiAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAoe3B9JSkiKSkgJT4lCiAgYWRkX3AodGVzdCA9IGFsbF9jYXRlZ29yaWNhbCgpIH4gImZpc2hlci50ZXN0IiwgcHZhbHVlX2Z1biA9IH5zdHlsZV9wdmFsdWUocC5hZGp1c3QoLngsIG1ldGhvZCA9ICJib25mZXJyb25pIikpKSAlPiUKICBib2xkX2xhYmVscygpCkJ5Y3RETkFfTVJECgptZXJnZWRfdGFibGUgPC0gdGJsX21lcmdlKHRibHM9bGlzdChPdmVyYWxsLCBCeWN0RE5BX01SRCkpCm1lcmdlZF90YWJsZQoKZml0MSA8LSBhc19mbGV4X3RhYmxlKAogIG1lcmdlZF90YWJsZSwKICBpbmNsdWRlID0gZXZlcnl0aGluZygpLAogIHJldHVybl9jYWxscyA9IEZBTFNFLAogIHN0cmlwX21kX2JvbGQgPSBUUlVFKQpmaXQxCnNhdmVfYXNfZG9jeChmaXQxLCBwYXRoPSAifi9Eb3dubG9hZHMvbWVyZ2VkX3RhYmxlLmRvY3giKQpgYGAKCgojRGV0ZWN0aW9uIGN0RE5BIHJhdGVzIGJhc2VkIG9uIHNpdGVzIG9mIHJlbGFwc2UKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgTGl2ZXIgTWV0cyBEYXRhXzIwMjQwNjI2IENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkTGl2ZXJNZXRzPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQ9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBzdWJzZXQoY2lyY19kYXRhLCAhaXMubmEoUmVjLlNpdGUpKQoKIyBDcmVhdGUgYSB0YWJsZSBvZiBjb3VudHMgZm9yIHRoZSAiUmVjLlNpdGUiIHZhcmlhYmxlCnJlbHNpdGVfY291bnRzIDwtIHRhYmxlKGNpcmNfZGF0YSRSZWMuU2l0ZSkKcmVsc2l0ZV9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlbHNpdGVfY291bnRzKQpuYW1lcyhyZWxzaXRlX2RmKSA8LSBjKCJSZWxTaXRlIiwgIkNvdW50IikKY2lyY19kYXRhX3Bvc19tcmQgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJQT1NJVElWRSIsXQpjaXJjX2RhdGFfcG9zX2FueXRpbWUgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hbnl0aW1lPT0iUE9TSVRJVkUiLF0KcG9zX2NvdW50c19tcmQgPC0gdGFibGUoY2lyY19kYXRhX3Bvc19tcmQkUmVjLlNpdGUpCnBvc19jb3VudHNfYW55dGltZSA8LSB0YWJsZShjaXJjX2RhdGFfcG9zX2FueXRpbWUkUmVjLlNpdGUpCnJlbHNpdGVfZGYkTVJEUG9zX0NvdW50IDwtIGlmZWxzZShpcy5uYShtYXRjaChyZWxzaXRlX2RmJFJlbFNpdGUsIG5hbWVzKHBvc19jb3VudHNfbXJkKSkpLCAwLCBwb3NfY291bnRzX21yZFttYXRjaChyZWxzaXRlX2RmJFJlbFNpdGUsIG5hbWVzKHBvc19jb3VudHNfbXJkKSldKQpyZWxzaXRlX2RmJE1SRFBvc19Db3VudFtpcy5uYShyZWxzaXRlX2RmJE1SRFBvc19Db3VudCldIDwtIDAKcmVsc2l0ZV9kZiRBbnl0aW1lUG9zX0NvdW50IDwtIGlmZWxzZShpcy5uYShtYXRjaChyZWxzaXRlX2RmJFJlbFNpdGUsIG5hbWVzKHBvc19jb3VudHNfYW55dGltZSkpKSwgMCwgcG9zX2NvdW50c19hbnl0aW1lW21hdGNoKHJlbHNpdGVfZGYkUmVsU2l0ZSwgbmFtZXMocG9zX2NvdW50c19hbnl0aW1lKSldKQpyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnRbaXMubmEocmVsc2l0ZV9kZiRBbnl0aW1lUG9zX0NvdW50KV0gPC0gMApyZWxzaXRlX2RmJFBlcmNlbnQgPC0gKHJlbHNpdGVfZGYkQ291bnQgLyBzdW0ocmVsc2l0ZV9kZiRDb3VudCkpICogMTAwCnJlbHNpdGVfZGYkTVJEUG9zX1BlcmNlbnQgPC0gKHJlbHNpdGVfZGYkTVJEUG9zX0NvdW50IC8gcmVsc2l0ZV9kZiRDb3VudCkgKiAxMDAKcmVsc2l0ZV9kZiRBbnl0aW1lUG9zX1BlcmNlbnQgPC0gKHJlbHNpdGVfZGYkQW55dGltZVBvc19Db3VudCAvIHJlbHNpdGVfZGYkQ291bnQpICogMTAwCnRvdGFsX29ic2VydmF0aW9ucyA8LSBzdW0ocmVsc2l0ZV9kZiRDb3VudCkKdG90YWxfcG9zX21yZCA8LSBzdW0ocmVsc2l0ZV9kZiRNUkRQb3NfQ291bnQpCnRvdGFsX3Bvc19hbnl0aW1lIDwtIHN1bShyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnQpCnRvdGFsX3JvdyA8LSBkYXRhLmZyYW1lKFJlbFNpdGUgPSAiVG90YWwiLCBDb3VudCA9IHRvdGFsX29ic2VydmF0aW9ucywgTVJEUG9zX0NvdW50ID0gdG90YWxfcG9zX21yZCwgQW55dGltZVBvc19Db3VudCA9IHRvdGFsX3Bvc19hbnl0aW1lLCBQZXJjZW50ID0gMTAwLCBNUkRQb3NfUGVyY2VudCA9ICh0b3RhbF9wb3NfbXJkIC8gdG90YWxfb2JzZXJ2YXRpb25zKSAqIDEwMCwgQW55dGltZVBvc19QZXJjZW50ID0gKHRvdGFsX3Bvc19hbnl0aW1lIC8gdG90YWxfb2JzZXJ2YXRpb25zKSAqIDEwMCkKcmVsc2l0ZV9kZiA8LSByYmluZChyZWxzaXRlX2RmLCB0b3RhbF9yb3cpCnByaW50KHJlbHNpdGVfZGYpCgpmdCA8LSBmbGV4dGFibGUocmVsc2l0ZV9kZikKZG9jIDwtIHJlYWRfZG9jeCgpICU+JQogIGJvZHlfYWRkX2ZsZXh0YWJsZSh2YWx1ZSA9IGZ0KQpwcmludChkb2MsIHRhcmdldCA9ICJyZWxzaXRlX2RmLmRvY3giKQpgYGAKCg==